1. 从注解入手找到对应核心类
最近工作中我都是基于注解实现AOP功能,常用的开启AOP的注解是@EnableAspectJAutoProxy,我们就从它入手。
上面的动图的流程的步骤就是:
@EnableAspectJAutoProxy
--> AspectJAutoProxyRegistrar
-->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary
-->AnnotationAwareAspectJAutoProxyCreator.class
虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。
2.画核心类类图,猜测核心方法
AnnotationAwareAspectJAutoProxyCreator的部分类图。
从类图看到了AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor,而AOP功能应该在创建完Bean之后执行,猜测AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor的postProcessAfterInitialization(实例化bean后处理)是核心方法。 查看AnnotationAwareAspectJAutoProxyCreator实现的postProcessAfterInitialization方法,实际该方法在其父类AbstractAutoProxyCreator中。
发现发现疑似方法wrapIfNecessary,查看其源码如下,发现createProxy方法。确定找对了地方。
即AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor的postProcessAfterInitialization方法,在该方法中由wrapIfNecessary实现了AOP的功能。 wrapIfNecessary中有2个和核心方法
getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器
createProxy为当前bean创建代理
要想明白核心流程还需要分析这2个方法。
3.读重点方法,理核心流程
3.1 getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器
查看源码如下,默认实现在AbstractAdvisorAutoProxyCreator中。
查阅findEligibleAdvisors方法,就干了3件事
找所有增强器,也就是所有@Aspect注解的Bean
找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。
对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。
AnnotationAwareAspectJAutoProxyCreator 重写了findCandidateAdvisors,下面我们看看具体实现了什么
3.1.1findCandidateAdvisors找所有增强器,也就是所有@Aspect注解的Bean
从该方法我们可以看到处理@Aspect注解的bean的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。 这个方法如下:
public List
List
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List
aspectNames = new ArrayList<>();
//找到所有BeanName String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 必须注意,bean会提前暴露,并被Spring容器缓存,但是这时还不能织入。 Class> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
//找到所有被@Aspect注解的类 aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//解析封装为Advisor返回 List
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this. if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List
for (String aspectName : aspectNames) {
List
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
这个方法可以概括为:
找到所有BeanName
根据BeanName筛选出被@Aspect注解的类
针对类中被Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解的方法,先按上边的注解顺序排序后按方法名称排序,每一个方法对应一个Advisor。
3.2 createProxy为当前bean创建代理。
3.2.1 创建代理的2种方式
众所周知,创建代理的常用的2种方式是:JDK创建和CGLIB,下面我们就看看这2中创建代理的例子。
3.2.1 .1 jdk创建代理的例子
3.2.1 .2 cglib创建代理的例子
3.2.1 .3 jdk创建代理与cglib创建代理的区别
3.2.2 Spring如何选择的使用哪种方式
Spring的选择选择如何代理时在DefaultAopProxyFactory 中。
config.isOptimize() 查看源码注释时发现,这个是配置使用cglib代理时,是否使用积极策略。这个值一般不建议使用!
config.isProxyTargetClass() 就是@EnableAspectJAutoProxy中的proxyTargetClass属性。
hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口
总结下Spring如何选择创建代理的方式:
如果设置了proxyTargetClass=true,一定是CGLIB代理
如果proxyTargetClass=false,目标对象实现了接口,走JDK代理
如果没有实现接口,走CGLIB代理
4.总结
Spring如何实现AOP?,您可以这样说:
AnnotationAwareAspectJAutoProxyCreator是AOP核心处理类
AnnotationAwareAspectJAutoProxyCreator实现了BeanProcessor,其中postProcessAfterInitialization是核心方法。
核心实现分为2步
getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器 createProxy为当前bean创建代理
getAdvicesAndAdvisorsForBean核心逻辑如下
a. 找所有增强器,也就是所有@Aspect注解的Bean
b. 找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。
c. 对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。
createProxy有2种创建方法,JDK代理或CGLIB
a. 如果设置了proxyTargetClass=true,一定是CGLIB代理
b. 如果proxyTargetClass=false,目标对象实现了接口,走JDK代理
c. 如果没有实现接口,走CGLIB代理
本次给大家分享一些学习资料,里面包括:(高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)以及Java进阶学习路线图,添加VX:19821111174 【验证】即可免费获取:最后,祝大家早日学有所成!