您现在的位置是:首页 >技术杂谈 >Spring AOP之EnableAspectJAutoProxy原理网站首页技术杂谈
Spring AOP之EnableAspectJAutoProxy原理
在《Spring AOP实现浅析三之执行代理》中,我们已熟悉了代理执行过程。本文中,我们将探究@EnableAspectJAutoProxy的底层实现:
- Spring中如何将@Aspect、 @Before等处理为Advisor?
- 在bean生命周期的哪个阶段创建了代理对象?
一 EnableAspectJAutoProxy注解
1.1 认识注解
要启用Spring AOP功能,得在配置类上添加@EnableAspectJAutoProxy。
这个注解有两个属性:
- proxyTargetClass:是否要创建基于子类的CGLIB代理,而不是基于Java接口的代理。默认值为false,即使用JDK代理实现。
- exposeProxy:将代理对象由AOP框架作为ThreadLocal公开,以便通过AopContext类获取。默认关闭。
可见,Spring AOP默认使用JDK动态代理,默认不将代理对象暴露给线程。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
1.2 导入AspectJAutoProxyRegistrar类
EnableAspectJAutoProxy注解通过@Import导入了AspectJAutoProxyRegistrar类。
该类实现了ImportBeanDefinitionRegistrar接口,复写了registerBeanDefinitions()方法,主要逻辑是:
- 向Spring容器添加AnnotationAwareAspectJAutoProxyCreator的beanDefinition;
- 获取注解的属性值,并设置到beanDefinition中。
新添加的beanName就是"org.springframework.aop.config.internalAutoProxyCreator"。
解析advisor、生成代理对象的逻辑都在AnnotationAwareAspectJAutoProxyCreator类中。
二 AbstractAutoProxyCreator类
AnnotationAwareAspectJAutoProxyCreator类是AbstractAutoProxyCreator的子类。
而AbstractAutoProxyCreator 是Spring AOP的核心类之一,它实现了SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware 接口,在postProcessAfterInitialization()方法中,实现了代理对象的创建。
wrapIfNecessary方法逻辑为:
- 跳过不需要代理的bean,如targetSource类型的bean、未命中切面的bean;
- 获取当前bean能匹配的Advisor,有则创建并返回代理对象,无则返回当前对象。
- 期间会维护缓存Map<Object, Boolean> advisedBeans。
如何创建代理对象,在《Spring AOP实现浅析 一》《Spring AOP实现浅析 二》《Spring AOP实现浅析 三》博文中,已做了详细介绍。
现在,我们详细看看一个bean如何匹配Advisor?
三 匹配Advisor
在子类AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean方法中,做了这些事:
- 找出Spring容器中所有的Advisor对象;
- 与当前bean匹配,得到适用的eligibleAdvisors;
- 向eligibleAdvisors中添加扩展的Advisor;
- 对eligibleAdvisors排序后返回。
3.1 找出所有Advisor对象
3.1.1 从容器中找Advisor对象
父类AbstractAdvisorAutoProxyCreator的findCandidateAdvisors方法,只会从容器中找所有Advisor类型的bean。
主要代码如下:
public List<Advisor> findAdvisorBeans() {
// 找所有Advisor类型的beanName
String[] advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
if (advisorNames.length == 0) {
return new ArrayList<>();
}
// 遍历names,获取bean
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
}
}
}
return advisors;
}
而子类AnnotationAwareAspectJAutoProxyCreator复写后,还会额外从@Aspect标注的类构建advisor。
3.1.2将@Aspect的类解析为Advisor
大体流程为:
- 当一个bean的类上有@Aspect注解时,就需要被处理;这样的bean将被缓存到aspectBeanNames中(一个List)。
- 将bean封装为BeanFactoryAspectInstanceFactory;从中解析advisor;
- 从类中解析到的Advisor会被缓存(避免重复解析)。
advisorFactory是一个ReflectiveAspectJAdvisorFactory类对象,完成了从method到advisor的转化。
- 找出类中没有@Pointcut的所有方法,包括hashCode、equals等;然后排序(按照@Around、@Before等注解顺序);
- 如果方法上没有Pointcut、Around、Before等注解,则跳过;
- 将注解中expression表达式封装为Pointcut对象;将方法封装为Advice对象;如:
-
- 将@Around的方法,封装为AspectJAroundAdvice对象;
- 将@Before的方法,封装为AspectJMethodBeforeAdvice对象;
- 一个Pointcut和一个Advice就组成了Advisor对象。
3.2 给bean匹配Advisor
将找到的所有advisor对象,依次与当前bean匹配,无非就是根据Pointcut的ClassFilter、MethodMatcher来判断。简化逻辑如下:
List<Advisor> matched = new ArrayList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
// ClassFilter
if(candidate.getClassFilter().matches(targetClass)){
Method[] methods = ReflectionUtils.getAllDeclaredMethods(targetClass);
// 方法匹配
for (Method method : methods) {
if (candidate.getMethodMatcher().matches(method, targetClass)){
matched.add(candidate);
break;
}
}
}
}
当bean中任意方法匹配了任意advisor,那么就需要为这个bean创建代理对象。
四 创建代理对象
调用AbstractAutoProxyCreator#createProxy方法,传入bean对象、beanName和匹配的Advisor集合,构建ProxyFactory对象来创建代理类。
Object proxy = createProxy(bean.getClass(), beanName,
specificInterceptors, new SingletonTargetSource(bean));
五 总结
- AbstractAdvisorAutoProxyCreator只会从容器中找所有Advisor类型的bean,而AnnotationAwareAspectJAutoProxyCreator类,还会从@Aspect标注的Bean中构建Advisor对象。
- @EnableAspectJAutoProxy,就是向Spring容器中添加了一个BeanPostProcessor接口实现(AnnotationAwareAspectJAutoProxyCreator),从而开启了AOP,在实例化后阶段为被切面命中的bean创建代理对象。