mirror of
https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
synced 2025-10-27 16:14:32 +08:00
feat(webmvc): Add method logging and configure Spring Boot AOP
- Added MethodRecording annotation to record method execution information - Implement MethodRecordingAspect for method recording - Add LoggerAutoConfiguration Automatic Configuration Class - Introduce CoroutineLogger coroutine log object - Update dependencies and configure Spring Boot AOP
This commit is contained in:
parent
c89f1f1737
commit
fc8bea06b3
@ -36,7 +36,6 @@ allprojects {
|
||||
ext {
|
||||
set(ProjectFlags.IS_ROOT_MODULE, false)
|
||||
set(ProjectFlags.USE_SPRING_BOOT_BOM, false)
|
||||
set(ProjectFlags.USE_SPRING_BOOT_WEB, false)
|
||||
}
|
||||
afterEvaluate {
|
||||
if (project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) {
|
||||
@ -58,11 +57,6 @@ subprojects {
|
||||
implementation(platform(libs.springBootDependencies.bom))
|
||||
}
|
||||
}
|
||||
if (project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT_WEB)) {
|
||||
dependencies {
|
||||
compileOnly(libs.springBootStarter.web)
|
||||
}
|
||||
}
|
||||
}
|
||||
val libs = rootProject.libs
|
||||
apply {
|
||||
@ -70,7 +64,6 @@ subprojects {
|
||||
plugin(libs.plugins.maven.publish.get().pluginId)
|
||||
plugin(libs.plugins.kotlin.jvm.get().pluginId)
|
||||
plugin(libs.plugins.axionRelease.get().pluginId)
|
||||
// plugin(libs.plugins.spring.dependency.management.get().pluginId)
|
||||
//导入仓库配置
|
||||
from(file("$configDir/repositories.gradle.kts"))
|
||||
// 导入源代码任务
|
||||
@ -91,6 +84,22 @@ subprojects {
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
val host = System.getenv("GEWUYOU_GITEA_HOST")
|
||||
host?.let {
|
||||
maven {
|
||||
isAllowInsecureProtocol = true
|
||||
name = "Gitea"
|
||||
url = uri("http://${it}/api/packages/gewuyou/maven")
|
||||
credentials(HttpHeaderCredentials::class.java) {
|
||||
name = "Authorization"
|
||||
value = "token ${System.getenv("GEWUYOU_GITEA_TOKEN")}"
|
||||
}
|
||||
authentication {
|
||||
create("header", HttpHeaderAuthentication::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
object ProjectFlags {
|
||||
const val IS_ROOT_MODULE = "isRootModule"
|
||||
const val USE_SPRING_BOOT_BOM = "useSpringBootBom"
|
||||
const val USE_SPRING_BOOT_WEB = "useSpringBootWeb"
|
||||
}
|
||||
3
forgeboot-webmvc/forgeboot-webmvc-logger-starter/.gitattributes
vendored
Normal file
3
forgeboot-webmvc/forgeboot-webmvc-logger-starter/.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/gradlew text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.jar binary
|
||||
40
forgeboot-webmvc/forgeboot-webmvc-logger-starter/.gitignore
vendored
Normal file
40
forgeboot-webmvc/forgeboot-webmvc-logger-starter/.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
HELP.md
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Kotlin ###
|
||||
.kotlin
|
||||
@ -0,0 +1,12 @@
|
||||
extra {
|
||||
// 需要SpringBootBom
|
||||
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
|
||||
}
|
||||
dependencies {
|
||||
implementation(project(Modules.Core.EXTENSION))
|
||||
implementation(libs.springBootStarter.aop)
|
||||
|
||||
implementation(libs.kotlinxCoroutines.reactor)
|
||||
|
||||
compileOnly(libs.springBootStarter.web)
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.gewuyou.forgeboot.webmvc.logger.annotation
|
||||
|
||||
/**
|
||||
* 记录方法的注解: 记录出参入参,方法执行耗时等信息
|
||||
*
|
||||
* @since 2025-01-23 14:22:11
|
||||
* @author gewuyou
|
||||
*/
|
||||
// 注解用于函数
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
// 在运行时可用
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
annotation class MethodRecording(val description: String = "",val printArgs: Boolean = true,val printResult: Boolean = true,val printTime: Boolean = true)
|
||||
@ -0,0 +1,86 @@
|
||||
package com.gewuyou.forgeboot.webmvc.logger.aspect
|
||||
|
||||
|
||||
import com.gewuyou.forgeboot.core.extension.log
|
||||
import com.gewuyou.forgeboot.webmvc.logger.annotation.MethodRecording
|
||||
import com.gewuyou.forgeboot.webmvc.logger.entities.CoroutineLogger
|
||||
import org.aspectj.lang.ProceedingJoinPoint
|
||||
import org.aspectj.lang.annotation.Around
|
||||
import org.aspectj.lang.annotation.Aspect
|
||||
/**
|
||||
* 方法记录切面
|
||||
*
|
||||
* 该切面用于拦截带有@MethodRecording注解的方法,记录方法的执行信息,包括方法开始执行、执行完成、执行失败等信息
|
||||
* 可以通过@MethodRecording注解的属性选择性打印方法的入参、返回值和执行耗时等信息
|
||||
*
|
||||
* @since 2025-01-23 14:25:04
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Aspect
|
||||
class MethodRecordingAspect {
|
||||
|
||||
/**
|
||||
* 环绕通知,用于在方法执行前后进行操作
|
||||
*
|
||||
* @param joinPoint 切入点,包含被拦截方法的信息
|
||||
* @param methodRecording 方法记录注解,包含配置信息
|
||||
* @return 方法的执行结果
|
||||
* @throws Throwable 方法执行过程中抛出的异常
|
||||
*/
|
||||
@Around("@annotation(methodRecording)")
|
||||
fun methodRecording(joinPoint: ProceedingJoinPoint, methodRecording: MethodRecording): Any? {
|
||||
// 获取方法名
|
||||
val methodName = joinPoint.signature.name
|
||||
// 获取类名
|
||||
val className = joinPoint.signature.declaringTypeName
|
||||
// 获取注解的描述信息
|
||||
val description = methodRecording.description
|
||||
// 获取方法的入参
|
||||
val args = joinPoint.args
|
||||
|
||||
// 安全地记录日志,防止日志记录失败
|
||||
CoroutineLogger.safeLog {
|
||||
// 构建日志字符串,包括方法开始执行的信息、注解的描述信息和入参信息
|
||||
val logStr = buildString {
|
||||
append("开始执行方法: $className.$methodName\n")
|
||||
append("$description\n")
|
||||
if (methodRecording.printArgs) {
|
||||
append("入参: ${args.joinToString()}\n")
|
||||
}
|
||||
}
|
||||
log.info(logStr)
|
||||
}
|
||||
|
||||
// 记录方法开始执行的时间
|
||||
val startTime = System.currentTimeMillis()
|
||||
|
||||
// 尝试执行方法
|
||||
return try {
|
||||
val result = joinPoint.proceed()
|
||||
val endTime = System.currentTimeMillis()
|
||||
val duration = endTime - startTime
|
||||
|
||||
// 安全地记录日志,记录方法执行完成的信息、返回值信息和执行耗时信息
|
||||
CoroutineLogger.safeLog {
|
||||
val logStr = buildString {
|
||||
append("方法 $className.$methodName 执行完成\n")
|
||||
if (methodRecording.printResult) {
|
||||
append("返回值: $result\n")
|
||||
}
|
||||
if (methodRecording.printTime) {
|
||||
append("执行耗时: ${duration}ms")
|
||||
}
|
||||
}
|
||||
log.info(logStr)
|
||||
}
|
||||
|
||||
result
|
||||
} catch (ex: Throwable) {
|
||||
// 如果方法执行失败,安全地记录错误日志
|
||||
CoroutineLogger.safeLog {
|
||||
log.error("方法 $className.$methodName 执行失败: ${ex.message}", ex)
|
||||
}
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.gewuyou.forgeboot.webmvc.logger.config
|
||||
|
||||
import com.gewuyou.forgeboot.core.extension.log
|
||||
import com.gewuyou.forgeboot.webmvc.logger.aspect.MethodRecordingAspect
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
/**
|
||||
* Logger自动配置
|
||||
*
|
||||
* 该类用于自动配置Logger,通过Spring的自动配置机制,自动加载和配置Logger
|
||||
* 它定义了一个Bean方法,用于创建和配置MethodRecordingAspect切面对象
|
||||
*
|
||||
* @since 2025-04-26 21:02:56
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Configuration
|
||||
open class LoggerAutoConfiguration {
|
||||
/**
|
||||
* 创建并返回一个MethodRecordingAspect切面对象
|
||||
*
|
||||
* 该方法定义了一个Bean,用于在Spring容器中创建并配置一个MethodRecordingAspect切面对象
|
||||
* MethodRecordingAspect切面对象用于记录方法的执行日志,以便于监控和调试
|
||||
*
|
||||
* @return MethodRecordingAspect切面对象
|
||||
*/
|
||||
@Bean
|
||||
open fun methodRecordingAspect(): MethodRecordingAspect {
|
||||
log.info("创建方法记录切面!")
|
||||
return MethodRecordingAspect()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.gewuyou.forgeboot.webmvc.logger.entities
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* 协程日志对象,用于在协程环境中安全地记录日志
|
||||
*
|
||||
* @since 2025-04-26 19:20:43
|
||||
* @author gewuyou
|
||||
*/
|
||||
object CoroutineLogger {
|
||||
// 创建一个协程作用域,使用SupervisorJob和IO调度器,适合进行IO密集型的日志记录任务
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
|
||||
/**
|
||||
* 安全地执行日志记录block,异常会被捕获并忽略,确保日志记录的稳定性
|
||||
*
|
||||
* @param block 日志记录的协程block,包含实际的日志记录逻辑
|
||||
*/
|
||||
fun safeLog(block: suspend () -> Unit) {
|
||||
// 在协程作用域中启动一个新的协程来执行日志记录任务
|
||||
scope.launch {
|
||||
try {
|
||||
// 尝试执行日志记录block
|
||||
block()
|
||||
} catch (ex: Exception) {
|
||||
// 吞噬日志错误,确保协程稳定运行,不会因单个日志记录失败而崩溃
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
com.gewuyou.forgeboot.webmvc.logger.config.LoggerAutoConfiguration
|
||||
@ -1,8 +1,9 @@
|
||||
extra {
|
||||
// 标记为根项目
|
||||
// 需要SpringBootBom
|
||||
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
|
||||
setProperty(ProjectFlags.USE_SPRING_BOOT_WEB, true)
|
||||
}
|
||||
dependencies {
|
||||
implementation(project(Modules.Core.EXTENSION))
|
||||
|
||||
compileOnly(libs.springBootStarter.web)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
kotlin-version = "2.0.0"
|
||||
kotlinxDatetime-version = "0.6.1"
|
||||
kotlinxSerializationJSON-version = "1.7.3"
|
||||
kotlinxCoroutines-version = "1.9.0"
|
||||
#kotlinxCoroutines-version = "1.9.0"
|
||||
axion-release-version = "1.18.7"
|
||||
spring-boot-version = "3.4.4"
|
||||
|
||||
@ -15,16 +15,20 @@ slf4j-version = "2.0.17"
|
||||
kotlinGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin-version" }
|
||||
kotlinxDatetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime-version" }
|
||||
kotlinxSerialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJSON-version" }
|
||||
kotlinxCoroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines-version" }
|
||||
|
||||
#kotlinxCoroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines-version" }
|
||||
kotlinxCoroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" }
|
||||
# kotlinx
|
||||
# 响应式协程库
|
||||
kotlinxCoroutines-reactor = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactor" }
|
||||
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j-version" }
|
||||
|
||||
springBootStarter-aop = { group = "org.springframework.boot", name = "spring-boot-starter-aop" }
|
||||
springBootStarter-web = { group = "org.springframework.boot", name = "spring-boot-starter-web" }
|
||||
springBootDependencies-bom = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "spring-boot-version" }
|
||||
|
||||
# Libraries can be bundled together for easier import
|
||||
[bundles]
|
||||
kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines"]
|
||||
kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines-core"]
|
||||
|
||||
[plugins]
|
||||
# 应用 Java 插件,提供基本的 Java 代码编译和构建能力
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user