概述
spring aop是spring特性之一,大部分情况下,我们使用aop特性都是想对功能方法的增强。想要透彻了解aop原理,最好需要提前了解两块内容,一个是java两种动态代理的实现,一个是spring容器初始化bean原理。
参考资料
1 spring源码分析容器整个生命周期图文详解
2java两种实现动态代理方式
sping使用aop代码示例
//1.开启aop
@EnableAspectJAutoProxy
@Configuration
public class MyConfig {
}
//2.定义切面
@Aspect
@Component
public class MyLogAspectJ {
//需要aop功能类,自定义切点表达式
@Pointcut(value = "execution(* com.example.springboottestservice.aop.TestService.*(..))")
public void pointcut(){}
@Before(value = "pointcut()")
public void logBefore(){
System.out.println("...logBefore...");
}
@After(value = "pointcut()")
public void logAfter(){
System.out.println("...logAfter...");
}
}
@EnableAspectJAutoProxy注解详解
使用@Import注解,导入了一个ImportBeanDefinitionRegistrar类,在执行BeanFactoryProcessor时候会发生回调,目的就是为了给容器添加一些组件
注册一个AnnotationAwareAspectJAutoProxyCreator类型bean,是一个BeanPostProcessor,对象创建后调用BeanPostProcessor的回调方法,返回一个代理对象,实现类增强
可以看到,aop实现是基于spring生命周期进行干预容器初始化和bean创建来完成的(蓝色部分是干预环节)
代理对象创建过程分析
BeanPostProcessor子接口的postProcessBeforeInstantiation(beanClass, beanName)在原始对象创建 前先执行,用来初始化通知部分(先初始化所有切面@Aspect)(只初始化一次会缓存下来)
BeanPostProcessor的生命周期方法postProcessAfterInitialization会在对象创建完成,装配完成,开始初始化进行调用,这个方法会将进行中的bean包装为一个代理对象
可以看到创建代理对象,直接寻找通知,然后构造MethodInterceptor,将回调和通知提前绑定,最后使用cglibv创建代理对象,返回的代理对象替换为真实在容器中的对象
代理对象执行过程分析
执行代理对象的方法,其实就是执行回调,回调期间通知都被包装成MethodInterceptor不同类型,实现不一样。所有的通知会组成一个拦截器链,一个一个执行
最佳实践
1.同一个类的方法互相调用,增强实效问题,最明显的就是事务实效
//解决方法非常简单,就是循环依赖注入自己,就变成bean发生调用了
@Component
public class F {
@Autowired
private F f;
public void a(){
System.out.println("F 执行 a");
}
public void b(){
System.out.println("F 执行 b");
}
public void ca(){
System.out.println("F 执行 ca");
f.a();
}
}
2.spring-cache实现原理,其实也就是使用了aop特性
依然是创建为代理对象,然后只是增强逻辑使用的是CacheInterceptor,用来在我们执行目标方法之前或者之后执行一些创建缓存的逻辑
总结
1.通过干预BeanFactoryPostProcessor来注册需要的bean,也就是用来干预bean创建的
AspectJAwareAdvisorAutoProxyCreator的类型的BeanPostProcessor
2.AspectJAwareAdvisorAutoProxyCreator创建过程中,生成代理对象,将要用到的通知方法和代理
对象进行绑定
3.执行方法,那么执行之前的回调,就完成了aop功能