基于最新Spring 5.x,详细介绍了DefaultAdvisorAutoProxyCreator的实现原理!
Spring AOP源码 系列文章
Spring AOP源码(1)—<aop:config/>AOP配置标签解析
Spring AOP源码(2)—AspectJAwareAdvisorAutoProxyCreator创建代理对象
Spring AOP源码(3)—invoke代理方法的调用与执行增强
Spring AOP源码(4)—基于注解的AOP源码解析以及AnnotationAwareAspectJAutoProxyCreator
Spring AOP源码(5)—DefaultAdvisorAutoProxyCreator自动代理创建者
DefaultAdvisorAutoProxyCreator原理
此前,我们已经讲解了AspectJAwareAdvisorAutoProxyCreator
和AnnotationAwareAspectJAutoProxyCreator
的源码,它们是最普通(普遍的)Spring AOP的实现原理,因此是最重要的。如果具有<aop:config/>
标签,那么默认使用AspectJAwareAdvisorAutoProxyCreator
来创建代理,如果具有<aop:aspectj-autoproxy/>
标签或者@EnableAspectJAutoProxy
注解,那么默认使用AnnotationAwareAspectJAutoProxyCreator
来创建代理。
DefaultAdvisorAutoProxyCreator
同样继承了AbstractAdvisorAutoProxyCreator
,是四种基于Advisor的自动代理创建者的实现之一:
DefaultAdvisorAutoProxyCreator使用的地方实际上并不是很多,在我们了解了AspectJAwareAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator的源码之后,我们知道Spring AOP的大部分处理流程都是在父类AbstractAutoProxyCreator和AbstractAdvisorAutoProxyCreator中完成的,这些具体的实现类仅仅是重写了某些方法来实现自己的特性,因此DefaultAdvisorAutoProxyCreator的原理也非常的简单!
DefaultAdvisorAutoProxyCreator和前两个AutoProxyCreator的大概区别如下:
sortAdvisors
:用于对已找到的Advisors链进行排序。- DefaultAdvisorAutoProxyCreator采用父类AbstractAdvisorAutoProxyCreator的默认sortAdvisors方,基于AnnotationAwareOrderComparator比较器的排序。
- 另两个AutoProxyCreator则重写了该方法,除了使用AnnotationAwareOrderComparator之外,还是用了aspectName、declarationOrder(声明顺序)来进行排序!
extendAdvisors
:用于对已找到的Advisors链进行扩展。- DefaultAdvisorAutoProxyCreator采用父类AbstractAdvisorAutoProxyCreator的默认extendAdvisors方法,该方法中什么也没做。
- 另两个AutoProxyCreator则重写了该方法,并且在Advisors链的头部添加一个特殊的Advisor——DefaultPointcutAdvisor,其内部的ExposeInvocationInterceptor用于暴露MethodInvocation。
shouldSkip
:判断是否需要跳过对给定bean进行的自动代理。- DefaultAdvisorAutoProxyCreator采用父类AbstractAutoProxyCreator的默认shouldSkip方法,逻辑是:如果beanName以beanCassName开头,并且以“.ORIGINAL”结束,那么返回true,表示当前bean应该采用原始实例,禁止代理,否则返回false。
- 另两个AutoProxyCreator则重写了该方法,将会通过findCandidateAdvisors方法查找beanFactory中的所有Advisor类型的通知器bean定义并且初始化(这个方法在其他地方也会调用),如果存在AspectJPointcutAdvisor类型的通知器实例,并且beanName等于aspectName,即表示当前的bean属于这个通知器的切面方法类bean,那么不应该拦截切面方法类的方法,直接返回true,表示跳过。否则在最后会才会调用父类的逻辑。
isEligibleAdvisorBean
:在findAdvisorBeans(查找候选Advisors)方法中,根据通知器的beanName判断通知器bean是否是合格的候选通知器。- 另两个AutoProxyCreator使用了父类AbstractAdvisorAutoProxyCreator的逻辑,默认始终返回true,也就是不根据名称筛选。
- DefaultAdvisorAutoProxyCreator则重写了该方法,支持beanName具有给定前缀的通知器bean才能够算作候选Advisor通知器。这也是DefaultAdvisorAutoProxyCreator最大的功能点和特点,是我们下面重点学习的地方!
DefaultAdvisorAutoProxyCreator支持beanName具有给定前缀的通知器bean才能够算作候选Advisor通知器。它提供了advisorBeanNamePrefix属性用来手动设置前缀:
@Nullable
private String advisorBeanNamePrefix;
/**
* 设置Advisor通知器 beanName 的前缀
*/
public void setAdvisorBeanNamePrefix(@Nullable String advisorBeanNamePrefix) {
this.advisorBeanNamePrefix = advisorBeanNamePrefix;
}
/**
* 获取Advisor通知器 beanName 的前缀
*/
@Nullable
public String getAdvisorBeanNamePrefix() {
return this.advisorBeanNamePrefix;
}
DefaultAdvisorAutoProxyCreator还实现了BeanNameAware
接口,容器中的DefaultAdvisorAutoProxyCreator在实例化完毕之后的initializeBean
初始化方法中,首先就会调用BeanNameAware接口的setBeanName
方法,并将当前DefaultAdvisorAutoProxyCreator的beanName传递到方法参数中!
DefaultAdvisorAutoProxyCreator的setBeanName
方法实现如下,它的目的就是在没有配置advisorBeanNamePrefix的时候,设置默认的前缀为beanName+"."
。
/**
* 默认的前缀的点
*/
public static final String SEPARATOR = ".";
/**
* bean实例创建完毕之后自动回调的方法,将当前创建的bean的beanName传递进来
*
*/
@Override
public void setBeanName(String name) {
//如果未设置Advisor通知器 beanName 的前缀,那么使用beanName+"."作为默认前缀
if (this.advisorBeanNamePrefix == null) {
this.advisorBeanNamePrefix = name + SEPARATOR;
}
}
当然,我们也可以通过usePrefix
属性手动控制是否开启前缀匹配,默认不启用,即所有的Advisor都是候选Advisor。
/**
* 是否启用前缀匹配的标志,默认不启用,即所有的Advisor都是候选Advisor
*/
private boolean usePrefix = false;
/**
* 设置启用标志
*/
public void setUsePrefix(boolean usePrefix) {
this.usePrefix = usePrefix;
}
/**
* 获取启用标志
*/
public boolean isUsePrefix() {
return this.usePrefix;
}
最后就是我们的isEligibleAdvisorBean
方法了,它也非常的简单,用于判断是否是合格的候选AdvisorBean。如果启用前缀匹配,那么通过beanName匹配前缀,否则默认返回true。
/**
* 判断是否是合格的候选AdvisorBean
* <p>
* 如果启用前缀匹配,那么beanName匹配前缀,否则默认返回true
*
* @param beanName 某个Advisor的beanName
*/
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
//如果没有启用前缀匹配,那么直接返回true,表示合格
if (!isUsePrefix()) {
return true;
}
//那么如果prefix不为null并且当前Advisor的beanName以指定的前缀开始,那么说明合格,否则返回false
String prefix = getAdvisorBeanNamePrefix();
return (prefix != null && beanName.startsWith(prefix));
}
是的,DefaultAdvisorAutoProxyCreator介绍完了,它就是这么简单……当然这里的“简单”是建立在我们已经熟悉了至少是AspectJAwareAdvisorAutoProxyCreator自动代理创建者的源码之后,而AspectJAwareAdvisorAutoProxyCreator的源码我们此前就讲过了!
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!