Spring AOP 实现原理
Spring AOP(面向切面编程)是 Spring Framework 提供的一种编程方式,它允许开发者将横切关注点(如日志、事务管理、安全性等)从业务逻辑中分离出来,从而使代码更具模块化和可维护性。Spring AOP 采用动态代理的方式,在程序运行时将切面(Aspect)织入到目标对象的代码中。
1. 切面(Aspect)
AOP 的核心,它是增强(Advice)和切点(Pointcut)的结合体。切面用于定义在哪些位置和何时应用增强。
2. 连接点(Joinpoint)
程序执行过程中的某个点,如方法调用、构造函数调用等。
3. 通知(Advice)
用于定义在连接点处执行的行为。通知可以分为多种类型,如前置通知、后置通知、异常通知等。
- 前置通知(Before):在方法调用前执行。
- 后置通知(After):在方法执行后执行,无论方法是否正常返回。
- 环绕通知(Around):环绕通知可以控制目标方法是否执行,并且能够修改方法的返回值。
- 异常通知(After Throwing):在方法抛出异常时执行。
- 最终通知(After Returning):在方法执行完毕(正常返回)时执行。
4. 切点(Pointcut)
定义了通知应用的时机,通常通过表达式来匹配方法。
5. 代理(Proxy)
Spring AOP 通过动态代理来织入切面。代理对象充当目标对象和调用者之间的中介,在调用目标方法时,代理对象会根据切点规则执行通知。
代理方式:
- JDK 动态代理:当目标类实现了接口时,Spring AOP 会生成一个 JDK 动态代理类来增强目标方法。
- CGLIB 代理:当目标类没有实现接口时,Spring AOP 会使用 CGLIB 生成目标类的子类来增强方法。
6. 案例实现
假设你的目标是记录方法调用的日志
6.1 添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
6.2 创建服务类(目标类)
创建一个简单的服务类,提供一个方法供 AOP 代理增强。
package com.example.aopdemo.service;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public String sayHello(String name) {
return "Hello, " + name;
}
public int add(int a, int b) {
return a + b;
}
}
6.3 创建切面类
切面类包含定义通知(前置通知、后置通知、环绕通知)和切点的代码。
package com.example.aopdemo.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
@Component
public class MyAspect {
// 定义切点:对 MyService 中的所有方法进行拦截
@Pointcut("execution(* com.example.aopdemo.service.MyService.*(..))")
public void myServiceMethods() {}
// 前置通知:在方法执行前调用
@Before("myServiceMethods()")
public void beforeMethod() {
System.out.println("Before method execution");
}
// 后置通知:在方法执行后调用,无论是否抛出异常
@After("myServiceMethods()")
public void afterMethod() {
System.out.println("After method execution");
}
// 环绕通知:控制目标方法的执行,并且可以修改返回值
@Around("myServiceMethods()")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Around before method execution");
Object result = joinPoint.proceed(); // 执行目标方法
System.out.println("Around after method execution");
return result;
}
// 返回值通知:方法成功执行之后执行
@AfterReturning(value = "myServiceMethods()", returning = "result")
public void afterReturningMethod(Object result) {
System.out.println("After Returning: Method executed successfully. Result = " + result);
}
}
6.4 启动类
Spring Boot 启动类,包含主方法,加载 Spring 应用上下文并运行。
package com.example.aopdemo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.example.aopdemo.service.MyService;
@SpringBootApplication
public class AopDemoApplication {
public static void main(String[] args) {
SpringApplication.run(AopDemoApplication.class, args);
}
@Bean
public CommandLineRunner run(MyService myService) {
return args -> {
// 测试方法调用,查看 AOP 日志输出
System.out.println(myService.sayHello("Alice"));
System.out.println("Addition Result: " + myService.add(10, 20));
};
}
}
6.5 输出日志
运行应用后,你会在控制台看到如下输出:
Around before method execution
Before method execution
Hello, Alice
Around after method execution
After Returning: Method executed successfully. Result = Hello, Alice
Around before method execution
Before method execution
Addition Result: 30
Around after method execution
After Returning: Method executed successfully. Result = 30
6.6 解释
- 前置通知(@Before):在方法执行之前执行,输出 Before method execution。
- 后置通知(@After):在方法执行之后执行,输出 After method execution。
- 环绕通知(@Around):能够控制目标方法的执行,可以修改返回值,输出 Around before 和 Around after。
- 返回值通知(@AfterReturning):当方法成功执行后执行,输出 After Returning,并显示方法的返回值。
7. 总结
Spring AOP 是通过代理方式来实现的,能够在方法执行前后动态插入代码。
使用 AOP 可以帮助我们解耦横切关注点(如日志、事务管理、权限控制等),使得代码更简洁易维护。
431



被折叠的 条评论
为什么被折叠?



