文章目录
一、什么是Spring的AOP?
AOP(面向切面编程,Aspect-Oriented Programming)
是一种编程范式,它允许程序员将跨越多个模块的关注点(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,以提高代码的可重用性和模块化。Spring AOP 是 Spring Framework 提供的一种实现 AOP 的方式,通过动态代理在运行时拦截方法调用,执行横切关注点的逻辑。
核心概念:
切面(Aspect)
: 横切关注点的模块化表示,比如日志功能、事务管理。切面可以在多个应用模块中重用。连接点(Join Point)
: 程序执行中的某个特定点,比如方法调用或异常抛出。在 Spring AOP 中,连接点通常指方法的执行。通知(Advice)
: 在切面的特定位置执行的代码,比如方法执行前后。Spring 提供了多种通知类型,包括前置通知、后置通知、环绕通知等。切入点(Pointcut)
: 切入点定义了通知应用的具体连接点。切入点表达式用于匹配应用程序中需要增强的特定方法。引入(Introduction)
: 允许我们向现有的类中添加新方法或属性。目标对象(Target Object)
: 被通知的对象,即包含了横切关注点的对象。代理(Proxy)
: AOP 框架为目标对象创建的动态代理,通知通过代理在目标对象上应用。
二、实现一个自定义注解的日志功能 Starter
需求描述
我们需要创建一个 Spring Boot Starter,提供一个自定义注解 @LogExecution。这个注解可以应用在方法上,自动记录方法的全限定名、方法的参数以及方法的执行时间。目标是将日志记录功能封装在 Starter 中,以便在其他 Spring 项目中轻松复用。
实现步骤
1. 创建Spring Boot Starter项目
首先,创建一个新的 Maven 项目,并配置所需的依赖。
Maven pom.xml
:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2. 创建自定义注解
在 src/main/java
目录下创建一个自定义注解 @LogExecution
,用于标记需要记录日志的方法。
package com.example.logstarter.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecution {
}
3. 创建AOP切面类
创建一个 AOP 切面类,拦截标记了 @LogExecution
注解的方法,并记录方法名、参数和执行时间。使用 @Slf4j
注解来简化日志记录操作。
package com.example.logstarter.aspect;
import com.example.logstarter.annotation.LogExecution;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
@Slf4j
public class LogExecutionAspect {
@Around("@annotation(logExecution)")
public Object logMethodExecution(ProceedingJoinPoint joinPoint, LogExecution logExecution) throws Throwable {
long startTime = System.currentTimeMillis();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String methodName = methodSignature.getDeclaringTypeName() + "." + methodSignature.getName();
Object[] methodArgs = joinPoint.getArgs();
log.info("执行方法名: {}", methodName);
log.info("方法的参数: {}", Arrays.toString(methodArgs));
try {
return joinPoint.proceed();
} finally {
long executionTime = System.currentTimeMillis() - startTime;
log.info("方法 {} 执行耗时 {} ms", methodName, executionTime);
}
}
}
4. 创建自动配置类
创建一个自动配置类,用于在 Spring Boot 项目中自动注册切面类。
package com.example.logstarter.config;
import com.example.logstarter.aspect.LogExecutionAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class LogStarterAutoConfiguration {
@Bean
public LogExecutionAspect logExecutionAspect() {
return new LogExecutionAspect();
}
}
5. 配置 META-INF/spring.factories
在 src/main/resources/META-INF/spring.factories
文件中,配置自动配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.logstarter.config.LogStarterAutoConfiguration
6. 打包发布和使用
打包并发布这个 Starter,然后在其他 Spring Boot 项目中引入这个 Starter 作为依赖。
使用示例:
在其他项目中,通过 @LogExecution
注解标记方法,即可自动记录日志。
import com.example.logstarter.annotation.LogExecution;
import org.springframework.stereotype.Service;
@Service
public class ExampleService {
@LogExecution
public void performTask(String taskName, int taskId) {
// 执行任务逻辑
System.out.println("Executing task: " + taskName + " with ID: " + taskId);
}
}
运行结果
在应用启动后,当 performTask
方法被调用时,日志将会自动记录方法的全限定名、参数信息以及方法的执行时间。
INFO com.example.logstarter.aspect.LogExecutionAspect - 执行方法名: com.example.demo.service.ExampleService.performTask
INFO com.example.logstarter.aspect.LogExecutionAspect - 方法的参数: [SampleTask, 42]
INFO com.example.logstarter.aspect.LogExecutionAspect - 方法 com.example.demo.service.ExampleService.performTask 执行耗时 25 ms
总结
通过 Spring 的 AOP 功能,我们可以将日志记录功能解耦,并封装成一个独立的 Spring Boot Starter。在实际项目中,开发人员只需简单地使用 @LogExecution
注解,就能方便地获取方法执行时的重要信息。这种方式提高了代码的可维护性和复用性,并确保日志记录逻辑统一、可靠。