你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
2021-04-02 16:29
标签:总结 hash action throw 技术 生命周期 iss etc ISE ?%E6%9C%AC%E7%B3%BB%E5%88%97%E6%96%87%E7%AB%A0%EF%BC%9A 在上篇文章中(Spring中AOP相关的API及源码解析,原来AOP是这样子的)我们已经分析过了AOP的实现的源码,那么Spring是如何将AOP应用到Bean的生命周期的呢?这篇文章就带着大家来探究下这个问题。本文我们要分析的代码还是位于org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean这个方法中,在《我们来谈一谈Spring中的属性注入 》这篇文章中,我们已经分析过了populateBean这个方法, 所以本文我们接着来看看initializeBean这个方法,它主要干了这么几件事 对应源码如下: 因为在Spring官网阅读(九)Spring中Bean的生命周期(上)文章中我们已经对这个方法做过分析了,并且这个方法本身也比较简单,所以不再对这个方法做过多赘述,我们主要关注的就是Spring是如何将AOP应用到Bean的生命周期中的,对应的就是applyBeanPostProcessorsAfterInitialization这个方法,其源码如下: 实际上就是调用了所有后置处理器的postProcessAfterInitialization方法,在Spring中AOP相关的API及源码解析,原来AOP是这样子的一文中已经提到过了,@EnableAspectJAutoProxy注解实际上就是向容器中注册了一个AnnotationAwareAspectJAutoProxyCreator,这个类本身就是一个后置处理器,AOP代理就是由它在这一步完成的。 1、@EnableAspectJAutoProxy 通过@EnableAspectJAutoProxy注解向容器中注册一个AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,它本身也是一个BeanPostProcessor,这个BeanDefinition会在org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors这个方法中完成创建,如下图所示 2、postProcessBeforeInstantiation方法执行 执行AnnotationAwareAspectJAutoProxyCreator的postProcessBeforeInstantiation方法,实际上就是父类AbstractAutoProxyCreator的postProcessBeforeInstantiation被执行 对应源码如下: 3、postProcessAfterInitialization方法执行 4、wrapIfNecessary方法执行 关于创建代理的具体源码分析,在Spring中AOP相关的API及源码解析,原来AOP是这样子的一文中已经做了详细介绍,所以本文不再赘述,现在我们的重点将放在Spring是如何解析出来通知的,对应方法就是getAdvicesAndAdvisorsForBean,其源码如下: 第一步:调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean 第二步:调用org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors 第三步:调用org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors获取到所有的通知 第四步:org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors构建通知,这个方法比较长,我们就只分析其中的关键代码即可 第五步:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply 这个方法其实没啥好分析的,就是根据前面找出来的Advisor集合进行遍历,然后根据每个Advisor对应的切点来进行匹配,如何合适就返回,对应源码也比较简单,当然前提是你看过我之前那篇AOP源码分析的文章了. 这篇文章比较短,因为没有做很细节的源码分析,比较详细的源码分析已经放到上篇文章中了。最后我这里画个流程图总结一下AOP是怎么被应用到Bean的生命周期中的 实际这段代码还是跟循环依赖相关,关于循环依赖的文章,大家可以参考:面试必杀技,讲一讲Spring中的循环依赖 如果我的文章能帮到你,记得点个赞哈~! 我叫DMZ,一个在学习路上匍匐前行的小菜鸟! 程序员DMZ 你知道Spring是怎么将AOP应用到Bean的生命周期中的吗? 标签:总结 hash action throw 技术 生命周期 iss etc ISE 原文地址:https://blog.51cto.com/14890701/2518892
%E8%AF%BB%E6%BA%90%E7%A0%81%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E4%BB%8E%E7%AC%AC%E4%B8%80%E8%A1%8C%E8%AF%BB%E8%B5%B7
%E4%BD%A0%E7%9F%A5%E9%81%93Spring%E6%98%AF%E6%80%8E%E4%B9%88%E8%A7%A3%E6%9E%90%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%9A%84%E5%90%97%EF%BC%9F
%E9%85%8D%E7%BD%AE%E7%B1%BB%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%B7%BB%E5%8A%A0@Configuration%E6%B3%A8%E8%A7%A3%EF%BC%9F
br/>本系列文章:
读源码,我们可以从第一行读起
你知道Spring是怎么解析配置类的吗?
配置类为什么要添加@Configuration注解?
谈谈Spring中的对象跟Bean,你知道Spring怎么创建对象的吗?
这篇文章,我们来谈一谈Spring中的属性注入
Spring中AOP相关的API及源码解析,原来AOP是这样子的
推荐阅读:
Spring官网阅读 | 总结篇
Spring杂谈
本系列文章将会带你一行行的将Spring的源码吃透,推荐阅读的文章是阅读源码的基础!”
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
Bean生命周期中AOP的流程
// 这个方法的主要目的就是在不考虑通知的情况下,确认哪些Bean不需要被代理
// 1.Advice,Advisor,Pointcut类型的Bean不需要被代理
// 2.不是原始Bean被包装过的Bean不需要被代理,例如ScopedProxyFactoryBean
// 实际上并不只是这些Bean不需要被代理,如果没有对应的通知需要被应用到这个Bean上的话
// 这个Bean也是不需要被代理的,只不过不是在这个方法中处理的。
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
// 如果beanName为空或者为这个bean提供了定制的targetSource
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// advisedBeans是一个map,其中key是BeanName,value代表了这个Bean是否需要被代理
// 如果已经包含了这个key,不需要在进行判断了,直接返回即可
// 因为这个方法的目的就是在实例化前就确认哪些Bean是不需要进行AOP的
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 说明还没有对这个Bean进行处理
// 在这里会对SpringAOP中的基础设施bean,例如Advice,Pointcut,Advisor做标记
// 标志它们不需要被代理,对应的就是将其放入到advisedBeans中,value设置为false
// 其次,如果这个Bean不是最原始的Bean,那么也不进行代理,也将其value设置为false
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 是否为这个Bean提供了定制的TargetSource
// 如果提供了定制的TargetSource,那么直接在这一步创建一个代理对象并返回
// 一般不会提供
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
实际上也是执行父类AbstractAutoProxyCreator中的方法,对应源码如下:public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 什么时候这个判断会成立呢?
// 如果不出现循环引用的话,remove方法必定返回null
// 所以这个remove(cacheKey) != bean肯定会成立
// 如果发生循环依赖的话,这个判断就不会成立
// 这个我们在介绍循环依赖的时候再详细分析,
// 目前你只需要知道wrapIfNecessary完成了AOP代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 需要代理的话,在这里完成的代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 在postProcessBeforeInstantiation方法中可能已经完成过代理了
// 如果已经完成代理了,那么直接返回这个代理的对象
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 在postProcessBeforeInstantiation方法中可能已经将其标记为不需要代理了
// 这种情况下,也直接返回这个Bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 跟在postProcessBeforeInstantiation方法中的逻辑一样
// 如果不需要代理,直接返回,同时在advisedBeans中标记成false
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取可以应用到这个Bean上的通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果存在通知的话,说明需要被代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 到这里创建代理,实际上底层就是new了一个ProxyFactory来创建代理的
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 如果没有通知的话,也将这个Bean标记为不需要代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Object[] getAdvicesAndAdvisorsForBean(
Class> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 通过findEligibleAdvisors方法返回对应的通知
// 这个方法会返回所有能应用在指定的Bean上的通知
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List findEligibleAdvisors(Class> beanClass, String beanName) {
// 获取到所有的通知
List candidateAdvisors = findCandidateAdvisors();
// 从获取到的通知中筛选出能应用到这个Bean上的通知
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
// 这个方法的目的就是为了获取到所有的通知
protected List findCandidateAdvisors() {
// 先调用父类的方法,父类会去查找容器中所有属于Advisor类型的Bean
List advisors = super.findCandidateAdvisors();
// 这个类本身会通过一个aspectJAdvisorsBuilder来构建通知
// 构建的逻辑就是解析@Aspect注解所标注的类中的方法
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
// 最后返回这些通知
return advisors;
}
public List buildAspectJAdvisors() {
List
protected List findAdvisorsThatCanApply(
List candidateAdvisors, Class> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
总结
Spring源码的最后一点补充
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 1.实例化 ---> createBeanInstance
// 2.属性注入 ---> populateBean
// 3.初始化 ---> 完成初始化及AOP
// exposedObject 就是完成初始化后的Bean
// 省略部分代码,省略代码的作用已经在上面标明了
// 下面的代码实际上主要目的在于处理循环依赖
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 我们之前早期暴露出去的Bean跟现在最后要放到容器中的Bean不是同一个
// allowRawInjectionDespiteWrapping为false
// 并且当前Bean被当成依赖注入到了别的Bean中
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 获取到当前Bean所从属的Bean
String[] dependentBeans = getDependentBeans(beanName);
// 要得到真实的从属的Bean
Set
点赞、转发、在看,多谢多谢!
喜欢作者
文章标题:你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?
文章链接:http://soscw.com/index.php/essay/71461.html