• 你知道Spring是怎么将AOP应用到Bean的生命周期中的吗?


    Spring是如何将AOP应用到Bean的生命周期的呢?这篇文章就带着大家来探究下这个问题。本文我们要分析的代码还是位于
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean这个方法中,我们之前分析过了 populateBean这个方法,

    所以本文我们接着来看看initializeBean这个方法,它主要干了这么几件事

    1. 执行Aware接口中的方法
    2. 执行生命周期回调方法
    3. 完成AOP代理

    对应源码如下:

    1. protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    2. if (System.getSecurityManager() != null) {
    3. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    4. invokeAwareMethods(beanName, bean);
    5. return null;
    6. }, getAccessControlContext());
    7. }
    8. else {
    9. // 执行Aware接口中的方法
    10. invokeAwareMethods(beanName, bean);
    11. }
    12. Object wrappedBean = bean;
    13. if (mbd == null || !mbd.isSynthetic()) {
    14. // 调用InitDestroyAnnotationBeanPostProcessor
    15. // 的postProcessBeforeInitialization方法
    16. // 处理@PostContructor注解标注的方法
    17. // 另外有一部分aware方法也是在这里调用的
    18. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    19. }
    20. try {
    21. // 如果实现了InitializingBean,会调用afterPropertiesSet方法
    22. // 如果XML中配置了init-method属性,会调用对应的初始化方法
    23. invokeInitMethods(beanName, wrappedBean, mbd);
    24. }
    25. catch (Throwable ex) {
    26. throw new BeanCreationException(
    27. (mbd != null ? mbd.getResourceDescription() : null),
    28. beanName, "Invocation of init method failed", ex);
    29. }
    30. if (mbd == null || !mbd.isSynthetic()) {
    31. // 在这里完成AOP
    32. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    33. }
    34. return wrappedBean;
    35. }

    我们主要关注的就是Spring是如何将AOP应用到Bean的生命周期中的,对应的就是
    applyBeanPostProcessorsAfterInitialization这个方法,其源码如下:

    1. public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    2. throws BeansException {
    3. Object result = existingBean;
    4. for (BeanPostProcessor processor : getBeanPostProcessors()) {
    5. Object current = processor.postProcessAfterInitialization(result, beanName);
    6. if (current == null) {
    7. return result;
    8. }
    9. result = current;
    10. }
    11. return result;
    12. }

    实际上就是调用了所有后置处理器的
    postProcessAfterInitialization方法,,@EnableAspectJAutoProxy注解实际上就是向容器中注册了一个AnnotationAwareAspectJAutoProxyCreator,这个类本身就是一个后置处理器,AOP代理就是由它在这一步完成的。

    Bean生命周期中AOP的流程

    1、@EnableAspectJAutoProxy

    通过@EnableAspectJAutoProxy注解向容器中注册一个
    AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,它本身也是一个BeanPostProcessor,这个BeanDefinition会在org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors这个方法中完成创建,如下图所示

    2、postProcessBeforeInstantiation方法执行

    执行
    AnnotationAwareAspectJAutoProxyCreator的postProcessBeforeInstantiation方法,实际上就是父类AbstractAutoProxyCreator的postProcessBeforeInstantiation被执行

    对应源码如下:

    1. // 这个方法的主要目的就是在不考虑通知的情况下,确认哪些Bean不需要被代理
    2. // 1.Advice,Advisor,Pointcut类型的Bean不需要被代理
    3. // 2.不是原始Bean被包装过的Bean不需要被代理,例如ScopedProxyFactoryBean
    4. // 实际上并不只是这些Bean不需要被代理,如果没有对应的通知需要被应用到这个Bean上的话
    5. // 这个Bean也是不需要被代理的,只不过不是在这个方法中处理的。
    6. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    7. Object cacheKey = getCacheKey(beanClass, beanName);
    8. // 如果beanName为空或者为这个bean提供了定制的targetSource
    9. if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
    10. // advisedBeans是一个map,其中key是BeanName,value代表了这个Bean是否需要被代理
    11. // 如果已经包含了这个key,不需要在进行判断了,直接返回即可
    12. // 因为这个方法的目的就是在实例化前就确认哪些Bean是不需要进行AOP的
    13. if (this.advisedBeans.containsKey(cacheKey)) {
    14. return null;
    15. }
    16. // 说明还没有对这个Bean进行处理
    17. // 在这里会对SpringAOP中的基础设施bean,例如Advice,Pointcut,Advisor做标记
    18. // 标志它们不需要被代理,对应的就是将其放入到advisedBeans中,value设置为false
    19. // 其次,如果这个Bean不是最原始的Bean,那么也不进行代理,也将其value设置为false
    20. if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
    21. this.advisedBeans.put(cacheKey, Boolean.FALSE);
    22. return null;
    23. }
    24. }
    25. // 是否为这个Bean提供了定制的TargetSource
    26. // 如果提供了定制的TargetSource,那么直接在这一步创建一个代理对象并返回
    27. // 一般不会提供
    28. TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    29. if (targetSource != null) {
    30. if (StringUtils.hasLength(beanName)) {
    31. this.targetSourcedBeans.add(beanName);
    32. }
    33. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
    34. Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
    35. this.proxyTypes.put(cacheKey, proxy.getClass());
    36. return proxy;
    37. }
    38. return null;
    39. }

    3、postProcessAfterInitialization方法执行

    实际上也是执行父类AbstractAutoProxyCreator中的方法,对应源码如下:

    1. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    2. if (bean != null) {
    3. Object cacheKey = getCacheKey(bean.getClass(), beanName);
    4. // 什么时候这个判断会成立呢?
    5. // 如果不出现循环引用的话,remove方法必定返回null
    6. // 所以这个remove(cacheKey) != bean肯定会成立
    7. // 如果发生循环依赖的话,这个判断就不会成立
    8. // 这个我们在介绍循环依赖的时候再详细分析,
    9. // 目前你只需要知道wrapIfNecessary完成了AOP代理
    10. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
    11. // 需要代理的话,在这里完成的代理
    12. return wrapIfNecessary(bean, beanName, cacheKey);
    13. }
    14. }
    15. return bean;
    16. }

    4、wrapIfNecessary方法执行

    1. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    2. // 在postProcessBeforeInstantiation方法中可能已经完成过代理了
    3. // 如果已经完成代理了,那么直接返回这个代理的对象
    4. if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    5. return bean;
    6. }
    7. // 在postProcessBeforeInstantiation方法中可能已经将其标记为不需要代理了
    8. // 这种情况下,也直接返回这个Bean
    9. if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    10. return bean;
    11. }
    12. // 跟在postProcessBeforeInstantiation方法中的逻辑一样
    13. // 如果不需要代理,直接返回,同时在advisedBeans中标记成false
    14. if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    15. this.advisedBeans.put(cacheKey, Boolean.FALSE);
    16. return bean;
    17. }
    18. // 获取可以应用到这个Bean上的通知
    19. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    20. // 如果存在通知的话,说明需要被代理
    21. if (specificInterceptors != DO_NOT_PROXY) {
    22. this.advisedBeans.put(cacheKey, Boolean.TRUE);
    23. // 到这里创建代理,实际上底层就是new了一个ProxyFactory来创建代理的
    24. Object proxy = createProxy(
    25. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    26. this.proxyTypes.put(cacheKey, proxy.getClass());
    27. return proxy;
    28. }
    29. // 如果没有通知的话,也将这个Bean标记为不需要代理
    30. this.advisedBeans.put(cacheKey, Boolean.FALSE);
    31. return bean;
    32. }

    现在我们的重点将放在Spring是如何解析出来通知的,对应方法就是
    getAdvicesAndAdvisorsForBean,其源码如下:

    第一步:调用
    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

    1. protected Object[] getAdvicesAndAdvisorsForBean(
    2. Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    3. // 通过findEligibleAdvisors方法返回对应的通知
    4. // 这个方法回返回所有能应用在指定的Bean上的通知
    5. List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    6. if (advisors.isEmpty()) {
    7. return DO_NOT_PROXY;
    8. }
    9. return advisors.toArray();
    10. }

    第二步:调用
    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

    1. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    2. // 获取到所有的通知
    3. List<Advisor> candidateAdvisors = findCandidateAdvisors();
    4. // 从获取到的通知中筛选出能应用到这个Bean上的通知
    5. List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    6. extendAdvisors(eligibleAdvisors);
    7. if (!eligibleAdvisors.isEmpty()) {
    8. eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    9. }
    10. return eligibleAdvisors;
    11. }

    第三步:调用
    org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors获取到所有的通知

    1. // 这个方法的目的就是为了获取到所有的通知
    2. protected List<Advisor> findCandidateAdvisors() {
    3. // 先调用父类的方法,父类会去查找容器中所有属于Advisor类型的Bean
    4. List<Advisor> advisors = super.findCandidateAdvisors();
    5. // 这个类本身会通过一个aspectJAdvisorsBuilder来构建通知
    6. // 构建的逻辑就是解析@Aspect注解所标注的类中的方法
    7. if (this.aspectJAdvisorsBuilder != null) {
    8. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    9. }
    10. // 最后返回这些通知
    11. return advisors;
    12. }

    第四步:
    org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors构建通知,这个方法比较长,我们就只分析其中的关键代码即可

    1. public List<Advisor> buildAspectJAdvisors() {
    2. List<String> aspectNames = this.aspectBeanNames;
    3. if (aspectNames == null) {
    4. synchronized (this) {
    5. aspectNames = this.aspectBeanNames;
    6. if (aspectNames == null) {
    7. List<Advisor> advisors = new ArrayList<>();
    8. aspectNames = new ArrayList<>();
    9. // 会获取到容器中的所有BeanName
    10. String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
    11. this.beanFactory, Object.class, true, false);
    12. for (String beanName : beanNames) {
    13. // 如果对beanName配置了正则匹配的话,那么要按照正则表达式的匹配规则进行过滤
    14. // 默认是没有的,可以认为isEligibleBean始终返回true
    15. if (!isEligibleBean(beanName)) {
    16. continue;
    17. }
    18. // We must be careful not to instantiate beans eagerly as in this case they
    19. // would be cached by the Spring container but would not have been weaved.
    20. Class<?> beanType = this.beanFactory.getType(beanName);
    21. if (beanType == null) {
    22. continue;
    23. }
    24. // 判断类上是否添加了@Aspect注解
    25. if (this.advisorFactory.isAspect(beanType)) {
    26. aspectNames.add(beanName);
    27. AspectMetadata amd = new AspectMetadata(beanType, beanName);
    28. // 默认就是SINGLETON,代理切面对象是单例的
    29. if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
    30. // 最后从这个切面实例中解析出所有的通知
    31. // 关于通知解析的具体代码就不再分析了
    32. MetadataAwareAspectInstanceFactory factory =
    33. new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
    34. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
    35. if (this.beanFactory.isSingleton(beanName)) {
    36. this.advisorsCache.put(beanName, classAdvisors);
    37. }
    38. else {
    39. this.aspectFactoryCache.put(beanName, factory);
    40. }
    41. advisors.addAll(classAdvisors);
    42. }
    43. // 省略部分代码
    44. return advisors;
    45. }

    第五步:
    org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply

    1. protected List<Advisor> findAdvisorsThatCanApply(
    2. List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    3. ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    4. try {
    5. return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    6. }
    7. finally {
    8. ProxyCreationContext.setCurrentProxiedBeanName(null);
    9. }
    10. }

    这个方法其实没啥好分析的,就是根据前面找出来的Advisor集合进行遍历,然后根据每个Advisor对应的切点来进行匹配,如何合适就返回,对应源码也比较简单,当然前提是你看过我之前那篇AOP源码分析的文章了.

    总结

    这篇文章比较短,因为没有做很细节的源码分析,比较详细的源码分析已经放到上篇文章中了。最后我这里画个流程图总结一下AOP是怎么被应用到Bean的生命周期中的

    Spring源码的最后一点补充

    1. protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    2. throws BeanCreationException {
    3. // 1.实例化 ---> createBeanInstance
    4. // 2.属性注入 ---> populateBean
    5. // 3.初始化 ---> 完成初始化及AOP
    6. // exposedObject 就是完成初始化后的Bean
    7. // 省略部分代码,省略代码的作用已经在上面标明了
    8. // 下面的代码实际上主要目的在于处理循环依赖
    9. if (earlySingletonExposure) {
    10. Object earlySingletonReference = getSingleton(beanName, false);
    11. if (earlySingletonReference != null) {
    12. if (exposedObject == bean) {
    13. exposedObject = earlySingletonReference;
    14. }
    15. // 我们之前早期暴露出去的Bean跟现在最后要放到容器中的Bean不是同一个
    16. // allowRawInjectionDespiteWrapping为false
    17. // 并且当前Bean被当成依赖注入到了别的Bean中
    18. else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    19. // 获取到当前Bean所从属的Bean
    20. String[] dependentBeans = getDependentBeans(beanName);
    21. // 要得到真实的从属的Bean
    22. Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
    23. for (String dependentBean : dependentBeans) {
    24. // 移除那些仅仅为了类型检查而创建出来
    25. if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
    26. actualDependentBeans.add(dependentBean);
    27. }
    28. }
    29. if (!actualDependentBeans.isEmpty()) {
    30. // 抛出异常
    31. // 出现了循环依赖,并且实际存在容器中的Bean跟被当作依赖注入到别的Bean中的
    32. // 不是同一个对象,这个时候也报错
    33. }
    34. }
    35. }
    36. }
    37. // 注册bean的销毁回调
    38. try {
    39. registerDisposableBeanIfNecessary(beanName, bean, mbd);
    40. }
    41. catch (BeanDefinitionValidationException ex) {
    42. throw new BeanCreationException(
    43. mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    44. }
    45. return exposedObject;
    46. }

    实际这段代码还是跟循环依赖相关,循环依赖是Spring中一个比较重要的话题,不管是为了面试还是更好的了解清楚Spring的流程都很有必要去弄懂它

     

  • 相关阅读:
    OpenCV-Python小应用(六):车道线检测
    2022全球边缘计算大会深圳站,8/6深圳南山
    『亚马逊云科技产品测评』活动征文|如何搭建低成本亚马逊aws云服务器
    RabbitMQ实践——交换器(Exchange)绑定交换器
    ELK ----elasticsearch笔记增删改查等
    将主机1中的数据存到主机2的MySQL数据库中
    RDB、AOF 阻塞操作?
    通过OptaPlanner优化 COVID-19 疫苗接种预约安排(2)
    二十三种设计模式(待更)
    【GlobalMapper精品教程】021:利用控制点校正栅格图像
  • 原文地址:https://blog.csdn.net/m0_71777195/article/details/125540444