【Spring【AOP】】——21、@EnableAspectJAutoProxy注解详解?

news2024/11/28 3:27:34

在这里插入图片描述

📫作者简介:zhz小白
公众号:小白的Java进阶之路
专业技能:
1、Java基础,并精通多线程的开发,熟悉JVM原理
2、熟悉Java基础,并精通多线程的开发,熟悉JVM原理,具备⼀定的线上调优经验
3、熟悉MySQL数据库调优,索引原理等,⽇志原理等,并且有出过⼀篇专栏
4、了解计算机⽹络,对TCP协议,滑动窗⼝原理等有⼀定了解
5、熟悉Spring,Spring MVC,Mybatis,阅读过部分Spring源码
6、熟悉SpringCloud Alibaba体系,阅读过Nacos,Sentinel,Seata,Dubbo,Feign,Gateway核⼼源码与设计,⼆次开发能⼒
7、熟悉消息队列(Kafka,RocketMQ)的原理与设计
8、熟悉分库分表ShardingSphere,具有真实⽣产的数据迁移经验
9、熟悉分布式缓存中间件Redis,对其的核⼼数据结构,部署架构,⾼并发问题解决⽅案有⼀定的积累
10、熟悉常⽤设计模式,并运⽤于实践⼯作中
11、了解ElasticSearch,对其核⼼的原理有⼀定的了解
12、了解K8s,Jekins,GitLab
13、了解VUE,GO
14、⽬前有正在利⽤闲暇时间做互游游戏,开发、运维、运营、推销等

本人著作git项目:https://gitee.com/zhouzhz/star-jersey-platform,有兴趣的可以私聊博主一起编写,或者给颗star
领域:对支付(FMS,FUND,PAY),订单(OMS),出行行业等有相关的开发领域
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~

文章目录

  • 1、@EnableAspectJAutoProxy有什么用?
  • 2、@EnableAspectJAutoProxy的源码解析
    • 2.1、初入@EnableAspectJAutoProxy源码
    • 2.2、@Import注解引入AspectJAutoProxyRegistrar
    • 2.3、开始阅读AspectJAutoProxyRegistrar源码
    • 2.4、开始阅读AnnotationAwareAspectJAutoProxyCreator
      • 2.4.1、AnnotationAwareAspectJAutoProxyCreator的类结构图
      • 2.4.2、开始阅读AnnotationAwareAspectJAutoProxyCreator的源码,了解其内部运作
        • 2.4.2.1、debug一下AnnotationConfigApplicationContext
        • 2.4.2.2、org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>...)
        • 2.4.2.3、org.springframework.context.support.AbstractApplicationContext#refresh
        • 2.4.2.4、org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors
        • 2.4.2.5、org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)
        • 2.4.2.6、org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
        • 2.4.2.7、org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
        • 2.4.2.8、org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
        • 2.4.2.9、org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
        • 2.4.2.10、org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
        • 2.4.2.11、org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
        • 2.4.2.12、org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#setBeanFactory
        • 2.4.2.13、AnnotationAwareAspectJAutoProxyCreator是怎么执行的?
      • 2.4.3、汇总以下AnnotationAwareAspectJAutoProxyCreator的处理
      • 2.4.4、AnnotationAwareAspectJAutoProxyCreator的作用是什么呢?
        • 2.4.4.1、postProcessBeforeInstantiation
        • 2.4.4.2、postProcessAfterInitialization
  • 原文连接(本人其他平台)

1、@EnableAspectJAutoProxy有什么用?

  • @EnableAspectJAutoProxy代表我们可以开启注解版的AOP功能,也就是说我们要想使用注解版的AOP,就必须在启动类/配置类(@Configuration)中添加@EnableAspectJAutoProxy。

2、@EnableAspectJAutoProxy的源码解析

废话不多说,让我们来看一下@EnableAspectJAutoProxy的核心源码吧

2.1、初入@EnableAspectJAutoProxy源码

在这里插入图片描述

2.2、@Import注解引入AspectJAutoProxyRegistrar

首先看AspectJAutoProxyRegistrar之前我们可以先行去了解下@Import注解如何注册一个Bean,具体如下:【Spring【IOC】】——7、@Import注解给容器中快速导入一个组件
接着我们再来进入AspectJAutoProxyRegistrar中,可以发现它继承了ImportBeanDefinitionRegistrar,重写了其中的void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);方法,源码如下:
在这里插入图片描述

所以我们可以知道**@EnableAspectJAutoProxy注解使用AspectJAutoProxyRegistrar对象自定义组件,并将相应的组件添加到了IOC容器中。**
那么大家好不好奇为什么他要通过AspectJAutoProxyRegistrar去继承ImportBeanDefinitionRegistrar,然后在其实现方法中注册一个Bean呢?那么这个Bean是什么呢?接下来我们开始debug其源码,从而深入去探讨@EnableAspectJAutoProxy。

2.3、开始阅读AspectJAutoProxyRegistrar源码

我们先在AspectJAutoProxyRegistrar的registerBeanDefinitions方法中添加一个断点,如下
在这里插入图片描述

然后我们一直进去,先后会执行以下代码

  • org.springframework.aop.config.AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry)
    • org.springframework.aop.config.AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
      • org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired

一直到org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired中我们就可以看到其核心逻辑,代码如下:
在这里插入图片描述

我们可以发现他在第一次进来的时候其实会创建一个key为:org.springframework.aop.config.internalAutoProxyCreator
,value: AnnotationAwareAspectJAutoProxyCreator.class的RootBeanDefinition并返回。
然后我们执行完这个方法之后,就会回来到下面红圈里面的方法,这一行的本质是将注解中的所有属性转成Map。
在这里插入图片描述

具体的结果如下所示:
在这里插入图片描述

  • 通过AnnotationConfigUtils类的attributesFor()方法来获取@EnableAspectJAutoProxy注解的信息。
    • 判断proxyTargetClass属性的值是否为true
      • 若为true则调用AopConfigUtils类的forceAutoProxyCreatorToUseClassProxying()方法;
        • 在这里插入图片描述

        • 这里就是获取AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,然后往属性中设置"proxyTargetClass"=true

    • 判断exposeProxy属性的值是否为true
      • 若为true则调用AopConfigUtils类的forceAutoProxyCreatorToExposeProxy()方法,本质是暴露一些Bean
        • 在这里插入图片描述

        • 这里就是获取AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,然后往属性中设置"exposeProxy"=true。

至此AspectJAutoProxyRegistrar类就已经完结了。
综上所述,向Spring的配置类上添加@EnableAspectJAutoProxy注解之后,会向IOC容器中注册AnnotationAwareAspectJAutoProxyCreator,也就是创建注解装配模式的AspectJ切面自动代理创建器

2.4、开始阅读AnnotationAwareAspectJAutoProxyCreator

上面2.3中我们发现@EnableAspectJAutoProxy注解本质上是往容器中添加一个AnnotationAwareAspectJAutoProxyCreator类,那么我们是不是要去了解AnnotationAwareAspectJAutoProxyCreator是一个什么样的东西呢?

2.4.1、AnnotationAwareAspectJAutoProxyCreator的类结构图

在这里插入图片描述

2.4.2、开始阅读AnnotationAwareAspectJAutoProxyCreator的源码,了解其内部运作

首先我们可以通过debug程序,具体可以先去看一下前面的章节《20、搭建一个AOP测试环境?》,我们主要是根据这个程序去研究AnnotationAwareAspectJAutoProxyCreator后置处理器的实现。
我们可以先去看一下栈帧,如下
在这里插入图片描述

2.4.2.1、debug一下AnnotationConfigApplicationContext

首先我们debug之后,会发现他会先停在AnnotationConfigApplicationContext这个创建对象上,如下
在这里插入图片描述

2.4.2.2、org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>…)

然后接着来会进入到AnnotationConfigApplicationContext内部调用refresh()方法区刷新容器,刷新容器就是要把容器中的所有bean都创建出来,也就是说这就像初始化容器一样。
在这里插入图片描述

2.4.2.3、org.springframework.context.support.AbstractApplicationContext#refresh

我们会进入refresh()方法里面的,并且会执行到下面这一行重要代码,

//注册Bean处理器,然后拦截bean创建。
registerBeanPostProcessors(beanFactory);

在这里插入图片描述

2.4.2.4、org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors

然后我们进入registerBeanPostProcessors方法中,看一下其核心实现,她就是调用了 PostProcessorRegistrationDelegate的registerBeanPostProcessors(beanFactory, this)静态方法。代码如下:
在这里插入图片描述

2.4.2.5、org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)

首先我们先全局看一下这个方法的代码,代码如下:

	public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
		// WARNING: Although it may appear that the body of this method can be easily
		// refactored to avoid the use of multiple loops and multiple lists, the use
		// of multiple lists and multiple passes over the names of processors is
		// intentional. We must ensure that we honor the contracts for PriorityOrdered
		// and Ordered processors. Specifically, we must NOT cause processors to be
		// instantiated (via getBean() invocations) or registered in the ApplicationContext
		// in the wrong order.
		//
		// Before submitting a pull request (PR) to change this method, please review the
		// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
		// to ensure that your proposal does not result in a breaking change:
		// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
		//先按照类型拿到IOC容器中所有需要创建的后置处理器,即先获取IOC容器中已经定义了的需要创建对象的所有BeanPostProcessor
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		/**
		 * 在已有的BeanPostProcessor中,如下
		 * 0 = {ApplicationContextAwareProcessor@2260}
		 * 1 = {ApplicationListenerDetector@2261}
		 * 2 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@2262}
		 * 添加一个下面的BeanPostProcessor检查器,
		 * 3 = {PostProcessorRegistrationDelegate$BeanPostProcessorChecker@2264}
		 */
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			} else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

接着我们开始讲解一下这段代码的意思,让我们充分了解每一行的来源,然后我们进入到PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);方法中,此时会按照下面流程执行

  • 1、先按照类型拿到IOC容器中所有需要创建的后置处理器,即先获取IOC容器中已经定义了的需要创建对象的所有BeanPostProcessor。(Spring在创建IOC容器的时候会先传入配置类,然后配置类中会有一个注解@EnableAspectJAutoProxy,而这个注解会注册一个AnnotationAwareAspectJAutoProxyCreator后置处理器(看前面),还有一些spring默认的后置处理器和我们自定义的后置处理器,具体如下)。

在这里插入图片描述

接着我们继续看下去,发现他执行了,下面这行代码去添加一个beanPostProcessor,
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));具体意思如下:
在这里插入图片描述

然后我们我们可以继续看到其下面有四行代码,如下:

//实现了PriorityOrdered接口
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
//类型是MergedBeanDefinitionPostProcessor的BeanPostProcessor
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
//实现了Ordered接口
List<String> orderedPostProcessorNames = new ArrayList<>();
//原生的BeanPostProcessor
List<String> nonOrderedPostProcessorNames = new ArrayList<>();

其作用是什么呢?主要是分离BeanPostProcessor,不同的BeanPostProcessor的执行顺序不同,具体为上面的代码解释。

  • 优先注册实现了PriorityOrdered接口的BeanPostProcessor
    • 如果类型是MergedBeanDefinitionPostProcessor的BeanPostProcessor
  • 再给容器中注册实现了Ordered接口的BeanPostProcessor
  • 最后再注册没实现优先级接口的BeanPostProcessor

在这里插入图片描述

我们可以自行查看一下org.springframework.aop.config.internalAutoProxyCreator的Bean名称的组件,即是AnnotationAwareAspectJAutoProxyCreator,他的底层类ProxyProcessorSupport实现了Ordered,所以他最终会进入到orderedPostProcessorNames这个list中,代码如下:
在这里插入图片描述

接着他会按照以下顺序是去执行注册BeanPostProcessor,如下:

  • 注册是priority的BeanPostProcessor
  • 注册是ordered的BeanPostProcessor
  • 注册原生的BeanPostProcessor
  • 注册是priority并且类型是MergedBeanDefinitionPostProcessor的BeanPostProcessor
  • 注册一个ApplicationListenerDetector的检测器(注册一个新的)

然后这个方法我们就讲完了。

2.4.2.6、org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

然后他会按照下面的执行顺序去执行代码:

  • org.springframework.beans.factory.BeanFactory#getBean(java.lang.String, java.lang.Class)
    • org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String, java.lang.Class)
      • org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

就会执行到我们这个部分要讲的核心代码了,这段代码有点长,我们直接看核心,在这段代码中有个函数表达式,关于函数表达式的执行顺序,大家可以看一下下面的数字,他会按照0-4执行。
在这里插入图片描述
在这里插入图片描述

省略代码来看就是下面:

AbstractBeanFactory#200 
// 0
sharedInstance = this.getSingleton(beanName, () -> { 
    try {
        return this.createBean(beanName, mbd, args);// 3 
    } catch (BeansException var5) {
        this.destroySingleton(beanName); 
            throw var5;
    } 
});

DefaultSingletonBeanRegistry#113
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {// 1 
    singletonObject = singletonFactory.getObject();// 2
        ...// 4 
}

我们分析一下这段代码,他其实就是从容器中获取单例Bean,具体的逻辑也就是下一部分的核心代码逻辑。

2.4.2.7、org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

第一次创建Bean的时候,是会执行到下面的DefaultSingletonBeanRegistry类的getSingleton()方法中,如果是第一次获取单实例的Bean获取不到时,就会调用singletonObject = singletonFactory.getObject();也就是下面截图的代码那
在这里插入图片描述

2.4.2.8、org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

接着debug他就会到AbstractBeanFactory的doGetBean()方法中,我们可以见名思意发现他就是创建Bean的,也就是说如果getSingleton获取不到Bean的话,我们就通过createBean创建Bean。
在这里插入图片描述

2.4.2.9、org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

接着我们会经历很长的一部分调用,知道调到AbstractAutowireCapableBeanFactory#createBean方法,执行流程如下:

  • org.springframework.beans.factory.support.AbstractBeanFactory#createBean
    • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

源代码如下,他会一直执行到doCreateBean方法
在这里插入图片描述

2.4.2.10、org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

然后当他执行到doCreateBean()方法,准备创建Bean的时候,这个方法会做很多事情,比如Bean的实例化,Bean的属性填充,Bean的初始化,销毁等等,但是对于我们这个AnnotationAwareAspectJAutoProxyCreator的后置处理器来说,他是在执行到exposedObject = initializeBean(beanName, exposedObject, mbd);方法,就会处理的,因此我们直接看initializeBean()初始化方法。
在这里插入图片描述

接下来他会进入到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)方法中。

2.4.2.11、org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

在进入到initizeBean之后,他会进行一系列的aware回调,其中有一段逻辑他是他会当我们的Bean实现了BeanFactoryAware,他就会把BeanFactory设置成AbstractAutowireCapableBeanFactory,而恰巧我们的AnnotationAwareAspectJAutoProxyCreator他就实现了BeanFactoryAware,具体大家可以看上面的解释,然后他就又会去调用所有的BeanPostProcessor的postProcessBeforeInitialization()方法,再调用初始化方法,也就是init-method,InitializingBean的相关方法,最后执行BeanPostProcessor的postProcessAfterInitialization()方法。
在这里插入图片描述
在这里插入图片描述

我们上面讲到了他会执行BeanFactoryAware相关的实现类,那么我们是不是可以定位到org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#setBeanFactory方法

2.4.2.12、org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#setBeanFactory

他会进入到AbstractAdvisorAutoProxyCreator的setBeanFactory中去设置BeanFactory,然后会执行到initBeanFactory()中,去初始化BeanFactory。
在这里插入图片描述

然后就会调到AnnotationAwareAspectJAutoProxyCreator#initBeanFactory中执行以下代码,主要是创建两个类ReflectiveAspectJAdvisorFactory和BeanFactoryAspectJAdvisorsBuilderAdapter,相当于把之前创建的aspectJAdvisorFactory以及beanFactory重新包装了一下。
在这里插入图片描述

因此整个流程就讲完了。

2.4.2.13、AnnotationAwareAspectJAutoProxyCreator是怎么执行的?

AnnotationAwareAspectJAutoProxyCreator它实现了SmartInstantiationAwareBeanPostProcessor并且继承了InstantiationAwareBeanPostProcessor,所以他的初始化前后的方法名分别为postProcessBeforeInstantiation,postProcessAfterInstantiation,而在我们上面讲的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])方法中,在其里面调用了如下代码:
在这里插入图片描述

在resolveBeforeInstantiation()方法里面调用了applyBeanPostProcessorsBeforeInstantiation()和applyBeanPostProcessorsAfterInitialization()两个方法。
在这里插入图片描述

其内部的逻辑分别是,从而调用了继承InstantiationAwareBeanPostProcessor的类的两个实例化前后方法

@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
		return null;
	}

@Override
	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;
	}

所以我们可以得出结论:

  • AnnotationAwareAspectJAutoProxyCreator会在任何bean创建之前,先尝试返回bean的实例
  • AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前,会有一个拦截,因为它是InstantiationAwareBeanPostProcessor这种类型的后置处理器,然后会调用它的postProcessBeforeInstantiation()方法。

2.4.3、汇总以下AnnotationAwareAspectJAutoProxyCreator的处理

  • org.springframework.context.support.AbstractApplicationContext#refresh
  • org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors
  • org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)
  • org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String, java.lang.Class)
  • org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
  • org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
  • org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
  • 最后就是执行initializeBean的里面的
    • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
    • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
  • 至此AnnotationAwareAspectJAutoProxyCreator就创建完成了,最后拿到所有的BeanPostProcessor,然后调用beanFactory的addBeanPostProcessor()方法将BeanPostProcessor注册到BeanFactory中。(这里可以看一下PostProcessorRegistrationDelegate#registerBeanPostProcessors(ConfigurableListableBeanFactory,AbstractApplicationContext)里面的),我们可以看一下registerBeanPostProcessors(beanFactory, internalPostProcessors);因为AnnotationAwareAspectJAutoProxyCreator会放入internalPostProcessors中,就可以发现他的本质就是上面红色那句话。
    在这里插入图片描述
    在这里插入图片描述

2.4.4、AnnotationAwareAspectJAutoProxyCreator的作用是什么呢?

首先我们通过上面的内容可知,在每一个bean创建之前,都会调用**postProcessBeforeInstantiation()**方法,**postProcessAfterInitialization()**方法。所以我们重点看一下AnnotationAwareAspectJAutoProxyCreator的
**postProcessBeforeInstantiation()postProcessAfterInitialization()**方法。

2.4.4.1、postProcessBeforeInstantiation

我们直接看AbstractAutoProxyCreator的postProcessBeforeInstantiation方法,他是AnnotationAwareAspectJAutoProxyCreator的核心,具体代码如下:
在这里插入图片描述

解析:

  • 1、先获取缓存的key,可以发现如果BeanName为空,就返回BeanClass,BeanName不为空,就判断当前beanClass是否是FactoryBean,是的话就返回&+beanName,不是的话就返回beanName。
    在这里插入图片描述

  • 2、判断名为targetSourcedBeans的Set集合里面是否包含有这个bean的名称,但是targetSourcedBeans是一个空的集合

    • 2.1、判断当前bean是否在advisedBeans中
      • advisedBeans:里面保存了所有需要增强的bean的名称
      • 为什么叫需要增强的bean?简单理解就是通过aop切面代理后的bean,列如日志aop类大家应该都熟悉吧。
        在这里插入图片描述
  • 3、判断当前bean是否是基础类型,或者是否是切面(标注了@Aspect注解的)

    • 3.1、我们可以发现isInfrastructureClass方法中,他执行了两块代码,分别是
      • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#isInfrastructureClass
        在这里插入图片描述
      • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
        在这里插入图片描述
      • 可以总结出isInfrastructureClass:判断当前bean是否是基础类型,或者是否是切面(标注了@Aspect注解的),其中基础类型涉及的注解有Advice,Pointcut,Advisor,AopInfrastructureBean。
    • 3.2、判断是否需要跳过
      • 在这里首先是调用findCandidateAdvisors()方法找到候选的增强器的集合:所谓的增强器其实就是切面里面的那些通知方法,只不过,在这儿是把通知方法的详细信息包装成了一个Advisor,并将其存放在了一个List集合中,即增强器的集合,即是说,每一个通知方法都会被认为是一个增强器。并且每一个通知方法都是InstantiationModelAwarePointcutAdvisor类型的,并且我们还可以发现是@Aspect修饰的类的aop方法。
        在这里插入图片描述
        在这里插入图片描述

      • 判断当前Advisor是否是AspectJPointcutAdvisor这种类型的,如果是,那么返回true。然而在我们这肯定不是,因为都是InstantiationModelAwarePointcutAdvisor类型的,所以不会进,因此会调用super.shouldSkip(beanClass, beanName)

        • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#shouldSkip
          在这里插入图片描述
          • org.springframework.aop.framework.autoproxy.AutoProxyUtils#isOriginalInstance,这里会判断当前的beanName是否为空或者beanName的长度不等于beanClass的长度+“.ORIGINAL"的长度,是的话就返回false,不是的话就判断beanName的开始是否等于beanClass的名字和beanName的结束是否等于”.ORIGINAL"。
            在这里插入图片描述
  • 4、如果是配置类,比如我们前面的章节里面的MainConfig的话,那么3就会返回false,就不会执行if里面的语句。并且下面中TargetSource也会为空,所以postProcessBeforeInstantiation()方法整体会返回null。

因此,我们可以发现,在每次创建bean的时候,都会先调用postProcessBeforeInstantiation()方法,然后再调用postProcessAfterInitialization()方法。

2.4.4.2、postProcessAfterInitialization

在这里插入图片描述

解析(我们还是基于MainConfig来讲):

  • 1、首先我们看一下传入当前方法的Bean是否为空,我们很清晰的可以发现bean就是ManConfig,所以他要进入if。

在这里插入图片描述

  • 2、先获取缓存的key,可以发现如果BeanName为空,就返回BeanClass,BeanName不为空,就判断当前beanClass是否是FactoryBean,是的话就返回&+beanName,不是的话就返回beanName。所以对于我们当前来说,他返回的就是mainConfig。

在这里插入图片描述

  • 3、判断名为earlyProxyReferences的Set集合里面是否包含当前bean,在该Set集合里面我们可以看到之前已经代理过了什么,目前该Set集合是一个空集合。因为当前earlyProxyReferences是肯定不包括,所以会进入到wrapIfNecessary(bean, beanName, cacheKey)。
    在这里插入图片描述

  • 4、判断哪些情况下是需要包装的。(wrapIfNecessary()方法调用完之后,最终会给容器中返回当前组件使用cglib增强了的代理对象

    • 4.1、首先是拿到MainConfig这个bean的名称(即mainConfig),然后再来判断名为targetSourcedBeans的Set集合里面是否包含有这个bean的名称,只不过此时该Set集合是一个空集合。

    • 4.2、判断名为advisedBeans的Map集合里面是否包含有当前bean的名称。我在前面也说过了advisedBeans这个东东,它就是一个Map集合,里面保存了所有需要增强的bean的名称。

    • 4.3、由于这儿是第一次来处理当前bean,所以名为advisedBeans的Map集合里面是不包含MainConfig这个bean的名称的。

    • 4.4、判断当前bean是否是基础类型,或者是否是切面(标注了@Aspect注解的)
      在这里插入图片描述

      • 4.4.1、我们可以发现isInfrastructureClass方法中,他执行了两块代码,分别是

        • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#isInfrastructureClass
          在这里插入图片描述

        • org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
          在这里插入图片描述

        • 可以总结出isInfrastructureClass:判断当前bean是否是基础类型,或者是否是切面(标注了@Aspect注解的),其中基础类型涉及的注解有Advice,Pointcut,Advisor,AopInfrastructureBean。

      • 4.4.2、判断是否需要跳过

        • 在这里首先是调用findCandidateAdvisors()方法找到候选的增强器的集合:所谓的增强器其实就是切面里面的那些通知方法,只不过,在这儿是把通知方法的详细信息包装成了一个Advisor,并将其存放在了一个List集合中,即增强器的集合,即是说,每一个通知方法都会被认为是一个增强器。并且每一个通知方法都是InstantiationModelAwarePointcutAdvisor类型的,并且我们还可以发现是@Aspect修饰的类的aop方法。
          在这里插入图片描述
          在这里插入图片描述

        • 判断当前Advisor是否是AspectJPointcutAdvisor这种类型的,如果是,那么返回true。然而在我们这肯定不是,因为都是InstantiationModelAwarePointcutAdvisor类型的,所以不会进,因此会调用super.shouldSkip(beanClass, beanName)

          • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#shouldSkip
            在这里插入图片描述

            • org.springframework.aop.framework.autoproxy.AutoProxyUtils#isOriginalInstance,这里会判断当前的beanName是否为空或者beanName的长度不等于beanClass的长度+“.ORIGINAL"的长度,是的话就返回false,不是的话就判断beanName的开始是否等于beanClass的名字和beanName的结束是否等于”.ORIGINAL"。
              在这里插入图片描述
      • 4.4.3、如果上面两条件有一个是true的话,就设置增强advisedBeans的map为cacheKey,false。然后返回bean。

    • 4.5、获取当前bean的所有增强器,调用getAdvicesAndAdvisorsForBean()方法获取当前bean的所有增强器,也就是那些通知方法,最终封装成这样一个Object[] specificInterceptors数组。
      在这里插入图片描述

      • 4.5.1、org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean
        • 4.5.1.1、org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
          • 4.5.1.1.1、获取所有的mainConfig的这个类型的所有的可用的增强器
            在这里插入图片描述

            • 4.5.1.1.1.1、进入其中就可以发现,其第一步是获取候选的所有增强器,也就是@Aspect的各种定义的通知类型方法(前置,后置,环绕,后置。。。)
              在这里插入图片描述
              在这里插入图片描述
            • 4.5.1.1.1.2、找到候选的所有增强器,也就是说是来找哪些通知方法是需要切入到当前bean的目标方法中的。
              在这里插入图片描述
              • 4.5.1.1.1.2.1、org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply,它是用AopUtils工具类来找到所有能用的增强器(通知方法)的。
                在这里插入图片描述
                • 4.5.1.1.1.2.1.1、然后我们可以进入到org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply,看一下其核心源码,本质上就是表达式匹配所有可用的增强器,从而把他添加到一个list中,并返回
                  在这里插入图片描述

最后一个canApply的源码。
在这里插入图片描述

           - 4.5.1.1.1.3、如果eligibleAdvisors不为空,就会进行排序,也就是说调用哪些通知方法,是有顺序的。然后进行返回。

在这里插入图片描述
- 4.5.1.2、如果findEligibleAdvisors(beanClass, beanName)返回为空,就返回null,也就是空Object[],返回就正常返回。
在这里插入图片描述
- 4.5.2、现在specificInterceptors的Object[]数组里面已经具有了那些指定好的增强器,这些增强器其实就是要拦截目标方法执行的。
- 4.5.3、总结一下
- 找到候选的所有增强器,也就是说是来找哪些通知方法是需要切入到当前bean的目标方法中的
- 获取到能在当前bean中使用的增强器
- 给增强器排序

  • 4.6、保存当前bean在advisedBeans中,表示这个当前bean已经被增强处理了
    在这里插入图片描述

    • 接着进入到createProxy中,也就是最核心的创建代理的方法,具体代码流程如下:
      • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
        • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#buildProxy,这里我们只看最后一步,其他代码都是一些过滤。
          在这里插入图片描述

          • proxyFactory.getProxyClass(classLoader),一般情况下不会调用当前方法,因此我们可以看一下前面传进来的classOnly他是false,重点看下面这个。
          • proxyFactory.getProxy(classLoader)),具体代码如下,我们直接看一下getProxy的实现。
            在这里插入图片描述
            在这里插入图片描述
            在这里插入图片描述
            • 我们可以发现getProxy会有两个实现,一个是jdk,一个是cglib,spring会分析如果当前类是有实现接口的,那么就使用jdk来创建动态代理,如果当前类没有实现接口,此时jdk是没法创建动态代理的,那么自然就得使用cglib来创建动态代理了。对于我们当前来说是cglib,spring也可以设置所有的代理都用cglib,只需要配置类开启@EnableAspectJAutoPrxy(proxyTargetClass = true),具体的更详细的可以自行百度。
              在这里插入图片描述
  • 4.7、设置代理类,返回
    在这里插入图片描述
    总结:

  • 获取所有增强器,所谓的增强器就是切面里面的那些通知方法。

  • 然后再把这些增强器保存到代理工厂(即proxyFactory)中。

  • 为当前组件创建代理对象,并且会有两种形式的代理对象,它们分别如下,最终Spring会自动决定,是为当前组件创建jdk的动态代理,还是创建cglib的动态代理。

    • 一种是JdkDynamicAopProxy这种形式的,即jdk的动态代理
    • 一种是ObjenesisCglibAopProxy这种形式的,即cglib的动态代理

原文连接(本人其他平台)

https://www.yuque.com/zhzbaishen/ldbu6i/epbql4eoegtomgce?singleDoc# 《21、@EnableAspectJAutoProxy注解详解?》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/142929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker二进制安装

目录 1、选择安装目录 2、了解默认安装 3、Docker网络了解 docker官网 1、选择安装目录 安装包下载 链接&#xff1a;https://pan.baidu.com/s/1mbUl2XLnlN4xZuHbvRF-vg?pwdpdoq 提取码&#xff1a;pdoq docker官网 1、选择安装目录 docker指定数据存储目录到 /data/…

mysql 乐观锁和悲观锁

悲观锁介绍&#xff08;百科&#xff09;&#xff1a; 悲观锁&#xff0c;正如其名&#xff0c;它指的是对数据被外界&#xff08;包括本系统当前的其他事务&#xff0c;以及来自外部系统的事务处理&#xff09;修改持保守态度&#xff0c;因此&#xff0c;在整个数据处理过程中…

二叉树的一些练习题

前言 二叉树的简单题目&#xff0c;通过画栈帧图去理解过程。画一画&#xff0c;走一走递归过程&#xff0c;理解会更加深刻。 二叉树练习题前言二叉树的创建二叉树先序遍历创建PreCreat二叉树层次创建LevelCreat二叉树的销毁BinaryTreeDestory二叉树求节点个数BinaryTreeSize二…

关于C语言输入输出的逗号问题(小细节)

C语言的输入输出必须要遵循scanf和printf的格式&#xff0c;就是你是什么格式你就要输入什么。 一、输入问题 #include <stdio.h> int main() { int a,b;scanf("%d,%d",&a,&b);printf("ab%d",ab);return 0; } 这个程序我们可以看到它运行…

【雷达开源数据集 | 代尔夫特数据集(VOD),4D雷达、激光雷达和相机数据】

本文编辑&#xff1a;调皮哥的小助理 1、介绍 代尔夫特视图 &#xff08;VoD&#xff09; 数据集是一种新颖的汽车数据集&#xff0c;包含 8600 帧同步和校准的 64 层 LiDAR、&#xff08;立体&#xff09;摄像头和 31D 雷达数据&#xff0c;这些数据是在复杂的城市交通中采集…

《编码 - 代码分析》代码结构分析

1 代码结构分析概述 在编写代码时&#xff0c;要求要结构清晰、接口简单。如果代码结构过于复杂&#xff0c;会带来很多问题&#xff1a;代码很难被理解&#xff0c;不方便编写测试用例&#xff0c;容易隐藏错误&#xff0c;出现问题难以定位&#xff0c;修改代码容易产生新的…

基于Java+SpringBoot+vue+elementui的校园文具商城系统详细设计和实现

基于JavaSpringBootvueelementui的校园文具商城系统详细设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目录基…

前端学习框架

一&#xff0c;学习路线图 https://roadmap.sh/ 二&#xff0c;学习资源整理 https://developer.mozilla.org/zh-CN/docs/Learn // 学习web 的各种资源网站 三&#xff0c;知识整理 将前端分为三步走 JavaScript 语言&#xff08;模块一&#xff09;CSS 和 HTML&#x…

【Latex】1.Latex环境的安装与配置

文章目录前言1 安装环境2. 下载texstudio前言 LaTeX&#xff08;LATEX&#xff0c;音译“拉泰赫”&#xff09;是一种基于ΤΕΧ的排版系统&#xff0c;由美国计算机学家莱斯利兰伯特&#xff08;Leslie Lamport&#xff09;在20世纪80年代初期开发&#xff0c;利用这种格式&a…

sqlmap之绕过云锁waf

sql注入不会绕过WAF&#xff1f;关注我&#xff0c;让我带你由简入难实战各个WAF&#xff0c;前天我们实战了安全狗的WAF&#xff0c;今天先来看看比它难度更高的云锁WAF&#xff0c;你会绕吗&#xff1f;看我带你将它拿下 目录 一&#xff1a;环境配置 1.云锁WAF 2.sqli-l…

本地数仓项目(二)——搭建系统业务数仓详细流程

1 说明 本文基于《本地数据仓库项目(一)——本地数仓搭建详细流程》业务数据&#xff0c;在本地搭建系统业务数仓。 根据模拟sql脚本生成业务数据&#xff0c;依次执行生成业务数据即可。 sql脚本提供如下 链接&#xff1a;https://pan.baidu.com/s/1WX3xVMQvAApSUZMobWLiLQ…

Vue-cli创建项目的目录结构与子父组件之间的通信

一、Vue脚手架的使用1、通过命令行使用vue-cli的指令创建&#xff1a;vue init webpack 项目名称build文件夹&#xff1a; 用于webpack打包配置文件夹config文件夹&#xff1a;与webpack相关的配置文件夹|——- index.js&#xff1a;可以改变项目默认的端口号node_moudles&…

Vue3/ Vite 的使用介绍 、Vite 方式工作流程 与 传统方式工作流程区别

一. Vite 的使用介绍 优势: &#x1f4a1;极速的服务启动 使用了原生的 ESM文件 无需打包 ⚡️ 轻量快速的热重在 始终极快的模块热重载 &#x1f6e0;️丰富的功能 对于 typescript jsx css 等支持开箱即用 &#x1f4e6; 等等 二.Vite 方式工作流程 与 传统方式工作流程…

千万不要把Request传递到异步线程里面!有坑!

前几天在网上冲浪的时候看到一篇技术文章&#xff0c;讲的是他把一个 request 请求传递到了线程池里面&#xff0c;然后遇到了一个匪夷所思的情况。 他写了这篇文章&#xff0c;把自己针对这个问题的探索过程分享了出来&#xff1a; 《springboot 中如何正确的在异步线程中使用…

ACL命名实验

目录 一.ACL命名实验 1.实验要求&#xff1a; 2.配置全网通 配置主机地址 3.根据实验要求配置ACL 4.测试完成后再根据下一次要求继续配置 一.ACL命名实验 实验图片 1.实验要求&#xff1a; 要求 全网通 服务器上配置 web 服务和 ftp 服务 配置 命名的acl 列表 …

_Linux 进程信号-信号保存篇

文章目录前言阻塞信号1. 信号常见概念2. 在内核中的表示信号处理过程3. sigset_t4. 信号集操作函数sigprocmasksigpending5. 测试与验证实验一实验二实验三前言 上篇文章&#xff08;链接: _Linux 进程信号-基础篇&#xff09;我们了解了信号的基础概念以及信号如何发送的。 …

强化学习_06_pytorch-PPO实践(Pendulum-v1)

一、PPO简介 TRPO(Trust Range Policy Optimate)算法每一步更新都需要大量的运算&#xff0c;于是便有其改进版本PPO在2017年被提出。PPO 基于 TRPO 的思想&#xff0c;但是其算法实现更加简单。TRPO 使用泰勒展开近似、共轭梯度、线性搜索等方法直接求解。PPO 的优化目标与 T…

可观测性--数据源

文章目录监控数据来源端上访问应用程序业务监控基础设施可观测性核心概念日志&#xff08;Logging&#xff09;统计指标&#xff08;Metrics&#xff09;链路追踪&#xff08;Tracing&#xff09;三者之间关系监控数据来源 我们一般讲的数据观测&#xff0c;其实观测的就是从发…

【Linux】计算机软硬件体系结构

文章目录冯诺依曼体系结构操作系统(Operator System)什么是操作系统为什么要有操作系统操作系统是怎么实现管理的系统调用接口和库函数总结冯诺依曼体系结构 谈到计算机的硬件结构&#xff0c;第一个想到的必然是经典的冯诺依曼体系结构&#xff1a; 我们常见的计算机&#xf…

在购买低代码产品时,源码是必需的吗?

编者按&#xff1a;企业在采购软件或者平台时&#xff0c;到底需不需要源码&#xff1f;本文分析了源码交付的对于不同规模和情况企业的意义&#xff0c;并介绍了源码交付的低代码平台。关键词&#xff1a;源码交付&#xff0c;可视化设计&#xff0c;私有化部署&#xff0c;多…