mirror of
https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
synced 2025-10-28 06:04:23 +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 {
|
ext {
|
||||||
set(ProjectFlags.IS_ROOT_MODULE, false)
|
set(ProjectFlags.IS_ROOT_MODULE, false)
|
||||||
set(ProjectFlags.USE_SPRING_BOOT_BOM, false)
|
set(ProjectFlags.USE_SPRING_BOOT_BOM, false)
|
||||||
set(ProjectFlags.USE_SPRING_BOOT_WEB, false)
|
|
||||||
}
|
}
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
if (project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) {
|
if (project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) {
|
||||||
@ -58,11 +57,6 @@ subprojects {
|
|||||||
implementation(platform(libs.springBootDependencies.bom))
|
implementation(platform(libs.springBootDependencies.bom))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT_WEB)) {
|
|
||||||
dependencies {
|
|
||||||
compileOnly(libs.springBootStarter.web)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val libs = rootProject.libs
|
val libs = rootProject.libs
|
||||||
apply {
|
apply {
|
||||||
@ -70,7 +64,6 @@ subprojects {
|
|||||||
plugin(libs.plugins.maven.publish.get().pluginId)
|
plugin(libs.plugins.maven.publish.get().pluginId)
|
||||||
plugin(libs.plugins.kotlin.jvm.get().pluginId)
|
plugin(libs.plugins.kotlin.jvm.get().pluginId)
|
||||||
plugin(libs.plugins.axionRelease.get().pluginId)
|
plugin(libs.plugins.axionRelease.get().pluginId)
|
||||||
// plugin(libs.plugins.spring.dependency.management.get().pluginId)
|
|
||||||
//导入仓库配置
|
//导入仓库配置
|
||||||
from(file("$configDir/repositories.gradle.kts"))
|
from(file("$configDir/repositories.gradle.kts"))
|
||||||
// 导入源代码任务
|
// 导入源代码任务
|
||||||
@ -91,6 +84,22 @@ subprojects {
|
|||||||
password = System.getenv("GITHUB_TOKEN")
|
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 {
|
publications {
|
||||||
create<MavenPublication>("mavenJava") {
|
create<MavenPublication>("mavenJava") {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
object ProjectFlags {
|
object ProjectFlags {
|
||||||
const val IS_ROOT_MODULE = "isRootModule"
|
const val IS_ROOT_MODULE = "isRootModule"
|
||||||
const val USE_SPRING_BOOT_BOM = "useSpringBootBom"
|
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 {
|
extra {
|
||||||
// 标记为根项目
|
// 需要SpringBootBom
|
||||||
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
|
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
|
||||||
setProperty(ProjectFlags.USE_SPRING_BOOT_WEB, true)
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(Modules.Core.EXTENSION))
|
implementation(project(Modules.Core.EXTENSION))
|
||||||
|
|
||||||
|
compileOnly(libs.springBootStarter.web)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
kotlin-version = "2.0.0"
|
kotlin-version = "2.0.0"
|
||||||
kotlinxDatetime-version = "0.6.1"
|
kotlinxDatetime-version = "0.6.1"
|
||||||
kotlinxSerializationJSON-version = "1.7.3"
|
kotlinxSerializationJSON-version = "1.7.3"
|
||||||
kotlinxCoroutines-version = "1.9.0"
|
#kotlinxCoroutines-version = "1.9.0"
|
||||||
axion-release-version = "1.18.7"
|
axion-release-version = "1.18.7"
|
||||||
spring-boot-version = "3.4.4"
|
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" }
|
kotlinGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin-version" }
|
||||||
kotlinxDatetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime-version" }
|
kotlinxDatetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime-version" }
|
||||||
kotlinxSerialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJSON-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" }
|
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" }
|
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" }
|
springBootDependencies-bom = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "spring-boot-version" }
|
||||||
|
|
||||||
# Libraries can be bundled together for easier import
|
# Libraries can be bundled together for easier import
|
||||||
[bundles]
|
[bundles]
|
||||||
kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines"]
|
kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines-core"]
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
# 应用 Java 插件,提供基本的 Java 代码编译和构建能力
|
# 应用 Java 插件,提供基本的 Java 代码编译和构建能力
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user