Spring AOP 源码解析和应用
2023-10-01 01:29:11
1. Spring AOP简介
1.1 概念
Spring AOP(Aspect Oriented Programming)是一种面向切面编程的技术,它允许开发人员将应用程序的各个方面(如安全、事务、日志记录等)从业务逻辑中分离出来,以便于维护和重用。Spring AOP 的核心思想是通过代理(Proxy)来拦截和修改方法调用。
1.2 注解方式使用AOP
在Spring中,可以使用注解的方式来配置AOP,非常方便,只需要在目标类上添加相应的注解即可。例如,以下代码使用了@Aspect注解来定义一个切面,并使用了@Before注解来定义在方法执行前执行的通知:
@Aspect
public class LoggingAspect {
@Before("execution(* com.example.demo.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Method: " + joinPoint.getSignature().getName() + " is about to be executed");
}
}
1.3 xml方式使用AOP
除了使用注解的方式,Spring还支持使用xml的方式来配置AOP。使用xml的方式需要在Spring配置文件中定义切面和通知,然后在目标类上使用<aop:config>
标签来启用AOP。例如,以下代码使用了<aop:config>
标签来启用AOP,并使用了<aop:aspect>
标签来定义切面:
<aop:config>
<aop:aspect ref="loggingAspect">
<aop:before method="logBefore" pointcut="execution(* com.example.demo.service.*.*(..))"/>
</aop:aspect>
</aop:config>
1.4 抛出问题?
a. Advice的执行顺序?
对比上面两张图片,可以看到@Around、@After、@Before这三个Advice的执行顺序是:
- @Around
- @Before
- 目标方法
- @After
b. 不同的Advice类型能同时应用在一个切入点吗?
可以,不同的Advice类型可以同时应用在一个切入点上,Spring会按照一定的顺序执行这些Advice。例如,以下代码同时使用了@Before和@AfterReturning两个Advice:
@Aspect
public class LoggingAspect {
@Before("execution(* com.example.demo.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Method: " + joinPoint.getSignature().getName() + " is about to be executed");
}
@AfterReturning(pointcut = "execution(* com.example.demo.service.*.*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("Method: " + joinPoint.getSignature().getName() + " returned result: " + result);
}
}
2. Spring AOP 源码分析
Spring AOP 的核心实现是通过代理(Proxy)来拦截和修改方法调用。Spring AOP 提供了多种代理类型,包括JDK动态代理和CGLIB代理。JDK动态代理是基于Java的动态代理机制实现的,而CGLIB代理是基于CGLIB库实现的。
Spring AOP 的代理类是通过ProxyFactoryBean
类来创建的。ProxyFactoryBean
类是一个FactoryBean,它可以产生代理对象。ProxyFactoryBean
类通过调用AdvisedSupport
类的createAopProxy()
方法来创建代理对象。
AdvisedSupport
类是Spring AOP的核心类之一,它负责管理切面和通知。AdvisedSupport
类包含了一个Advisor
列表,Advisor
列表中包含了所有的切面和通知。AdvisedSupport
类还包含了一个TargetSource
对象,TargetSource
对象负责获取目标对象。
3. Spring AOP 使用示例
Spring AOP 可以用来实现各种各样的功能,包括安全、事务、日志记录、性能监控等。以下是一些 Spring AOP 的使用示例:
3.1 安全
Spring AOP 可以用来实现安全控制,例如,以下代码使用Spring AOP来控制对UserService
类中getUser()
方法的访问:
@Aspect
public class SecurityAspect {
@Before("execution(* com.example.demo.service.UserService.getUser(..))")
public void checkSecurity(JoinPoint joinPoint) {
// 检查当前用户是否有权限访问getUser()方法
if (!currentUser.hasPermission("USER_GET")) {
throw new SecurityException("Access denied");
}
}
}
3.2 事务
Spring AOP 可以用来实现事务管理,例如,以下代码使用Spring AOP来管理UserService
类中saveUser()
方法的事务:
@Aspect
public class TransactionAspect {
@Around("execution(* com.example.demo.service.UserService.saveUser(..))")
public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
// 开始事务
transactionManager.beginTransaction();
try {
// 执行目标方法
Object result = joinPoint.proceed();
// 提交事务
transactionManager.commit();
return result;
} catch (Throwable e) {
// 回滚事务
transactionManager.rollback();
throw e;
}
}
}
3.3 日志记录
Spring AOP 可以用来实现日志记录,例如,以下代码使用Spring AOP来记录UserService
类中getUser()
方法的调用:
@Aspect
public class LoggingAspect {
@AfterReturning(pointcut = "execution(* com.example.demo.service.UserService.getUser(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("Method: " + joinPoint.getSignature().getName() + " returned result: " + result);
}
}
4. 总结
Spring AOP 是一个强大的面向切面编程框架,它可以用来拦截和修改应用程序中的方法调用。Spring AOP 的核心思想是通过代理(Proxy)来拦截和修改方法调用。Spring AOP 可以用来实现各种各样的功能,包括安全、事务、日志记录、性能监控等。