Spring AOP实现过程

661 阅读15分钟

完整流程

spring aop源码解析

简略版

主线脉络:BeanPostProcessor -> target Object -> Proxy Object -> intercept target method

1.注册BeanProcessor:无论是通过xml还是注解方式启动Spring AOP,在启动过程中,都会注册一个xxxAutoProxyCreator后置处理器。后置处理器可以在目标对象的init-method前后执行某个方法
2.创建目标对象:过程是依次执行 构造方法 -> 设置属性 -> postProcessBeforeInitialization -> afterPropertiesSet -> init-method -> postProcessAfterInitialization
3.在执行postProcessAfterInitialization时,第1步注册的后置处理器就会获取当前对象匹配的所有增强器,如果匹配不到,直接返回;匹配到就进入创建代理对象
4.创建代理对象:过程是依次执行 获取增强器 -> Proxy Factory -> Aop Proxy -> proxy object。获取到的增强器会注入到代理工厂,代理工厂会根据proxyTargetClass属性值、目标类是否实现接口决定使用jdk还是cglib动态代理
5.拦截目标方法:当执行目标方法时,如果是jdk动态代理,会进入到JdkDynamicAopProxy#invoke方法,如果是cglib动态代理,会进入到CglibAopProxy#intercept方法,无论进入哪个方法,处理过程几乎一致。先获取目标方法上的拦截器链,如果为空,直接执行目标方法;非空,则创建MehotdInvocation对象,并调用proceed方法。
6.执行proceed:MehotdInvocation有一个属性用于记录当前拦截器的索引,如果发现索引等于拦截器数量-1,说明全部拦截器都执行完成,需要执行连接点方法。如果
不满足条件,通过索引从拦截器列表获取对应的拦截器,执行其invoke方法
7.拦截器的invoke:每个拦截器实现的invoke方法内容都不同,但是相同点是在invoke最后,继续调用methodInvocation#proceed,重复第6步,直到所有拦截器执行完成

完整版

ioc容器启动流程:
		1)、传入配置类,或者指定配置文件,创建ioc容器
		2)、注册配置类,调用refresh(),刷新容器;
	    3)、registerBeanPostProcessors(beanFactory),注册bean的后置处理器来方便拦截bean的创建;
             
              1)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
              2)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
              3)、最后注册没实现优先级接口的BeanPostProcessor;
              4)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
                  创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
                  1)、创建Bean的实例
                  2)、populateBean;给bean的各种属性赋值
                  3)、initializeBean:初始化bean;
                          1)、invokeAwareMethods():处理Aware接口的方法回调
                          2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
                          3)、invokeInitMethods();执行自定义的初始化方法
                          4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
                  4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
              5)、把BeanPostProcessor注册到BeanFactory中;beanFactory.addBeanPostProcessor(postProcessor);
              
=======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程====
  
                      
==============以下对象实例创建过程细节==================================                      
创建代理对象,可看成分为两步:先创建目标对象,再创建代理对象

创建目标对象:
          4)、finishBeanFactoryInitialization(beanFactory); 完成BeanFactory初始化工作;创建剩下的单实例bean
              1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
                  getBean->doGetBean()->getSingleton()->
              2)、创建bean
                  1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;
                  2)、createBean(); 创建bean;
			创建过程:执行构造函数 -> 属性设置 -> 各种xxxAware接口 -> postProcessBeforeInitialization -> afterPropertySet -> init-method -> postProcessAfterInitialization
--------------------------------------
创建代理对象
	1)、init-method执行前,调用postProcessBeforeInstantiation();
         不做任何处理(spring 5.1.x)
              
 	2)、init-method执行后,调用postProcessAfterInitialization();
          1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors
             1、找到候选的所有的增强器(增强器:哪些通知方法是需要切入当前bean方法的)
             2、获取到能在bean使用的增强器。
             3、给增强器排序
         2)、保存当前bean在advisedBeans中;
         3)、如果当前bean需要增强,创建当前bean的代理对象;
             1)、获取所有增强器(通知方法)
             2)、保存到proxyFactory
             3)、创建代理对象:Spring自动决定
                 JdkDynamicAopProxy(config);jdk动态代理;
                 ObjenesisCglibAopProxy(config);cglib的动态代理;
         4)、给容器中返回当前组件使用cglib增强了的代理对象;
         5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
         
======以下是目标方法的执行==============================================         
  	
  	3)、目标方法执行;容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
         1)、CglibAopProxy.intercept();拦截目标方法的执行
         2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
             1)、List<Object> interceptorList保存所有拦截器 5个
                 一个默认的ExposeInvocationInterceptor 和 4个增强器;
             2)、遍历所有的增强器,将其转为Interceptor;
                 registry.getInterceptors(advisor);
             3)、将增强器转为List<MethodInterceptor>;
                 如果是MethodInterceptor,直接加入到集合中
                 如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
                 转换完成返回MethodInterceptor数组;
			3)、如果没有拦截器链,直接执行目标方法;        
			4)、如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation 对象,
				并调用 Object retVal =  mi.proceed();
			5)、拦截器链的触发过程;        
				1)、如果没有拦截器则直接执行目标方法,或者 拦截器的索引 和 拦截器数组长度-1 大小一样(指定到了最后一个拦截器)就直接执行目标方法;
				2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;           
					拦截器链的机制,保证通知方法与目标方法的执行顺序;

注册后置处理器

我们可以通过@EnableAspectJAutoProxy开启spring aop功能,启动自动代理。从这个注解入手,看看它做了什么事情。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

可以看到,EnableAspectJAutoProxy有个@Import注解,导入一个AspectJAutoProxyRegistrar类,继续往下追踪

image-20201105151947846

跟踪到AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary,可以看到确实是注册AnnotationAwareAspectJAutoProxyCreator类的Bean信息

image-20201105152239506

AnnotationAwareAspectJAutoProxyCreator到底是啥呢??观察它的继承结构体系,我们发现它实现了BeanPostProcessor接口,因此它是一个后置处理器。我们都知道,BeanPostProcessor有两个方法,分别在实例对象的init-method方法前后执行。

image-20201105152501714

既然我们知道了AnnotationAwareAspectJAutoProxyCreator是个后置处理器,那它在什么时候注册呢??(注册时机)

通过仔细查找,在AbstractApplicationContext#refresh方法看到调用registerBeanPostProcessors方法,应该就在这里注册所有的后置处理器。

image-20201105154043339

一路追踪,找到PostProcessorRegistrationDelegate#registerBeanPostProcessors方法,里面代码很多,主要的意思是,按照实现PriorityOrdered、Ordered接口,没实现接口 的顺序依次注册后置处理器。

我们再回看上面的继承结构,发现AnnotationAwareAspectJAutoProxyCreator实现了Ordered接口,打个断点,看下啥情况。

image-20201105155435031

image-20201105155533256

可以清晰看到,此时只有一个实现ordered接口的后置处理器,那应该就是 AnnotationAwareAspectJAutoProxyCreator。怎么确认呢?对比它们的beanName就可以了。来,我们去找下AnnotationAwareAspectJAutoProxyCreator的beanName

我们刚刚已经定位到**@EnableAspectJAutoProxy会在AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary注册后置处理器,继续往里面跟踪,最终在AopConfigUtils#registerOrEscalateApcAsRequired找到AnnotationAwareAspectJAutoProxyCreator的beanName**。

image-20201105160915088

两个beanName匹配上了,所以可以确定,@EnableAspectJAutoProxy会在ioc容器启动时,注册一个xxxAutoProxyCreator后置处理器,在bean对象初始化方法执行前后拦截,进行某些操作,最终实现自动代理。

ioc容器启动流程:
		1)、传入配置类,或者指定配置文件,创建ioc容器
		2)、注册配置类,调用refresh(),刷新容器;
	    3)、registerBeanPostProcessors(beanFactory),注册bean的后置处理器来方便拦截bean的创建;
             
              1)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
              2)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
              3)、最后注册没实现优先级接口的BeanPostProcessor;
              4)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
                  创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
                  1)、创建Bean的实例
                  2)、populateBean;给bean的各种属性赋值
                  3)、initializeBean:初始化bean;
                          1)、invokeAwareMethods():处理Aware接口的方法回调
                          2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
                          3)、invokeInitMethods();执行自定义的初始化方法
                          4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
                  4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
              5)、把BeanPostProcessor注册到BeanFactory中;beanFactory.addBeanPostProcessor(postProcessor);

创建代理对象

问题:spring aop在什么时候创建代理对象?

Spring AOP配置

我们定义一个LagouBean,在它的print方法执行前调用切面方法。以下是配置

public class LagouBean {
	public void print() {
		System.out.println("print方法业务逻辑执行");
	}
}
    <bean id="lagouBean" class="com.lagou.edu.LagouBean"></bean>

	<!--aop配置-->
	<!--横切逻辑-->
	<bean id="logUtils" class="com.lagou.edu.LogUtils"></bean>

	<aop:config>
		<aop:aspect ref="logUtils">
			<aop:before method="beforeMethod" pointcut="execution(public void com.lagou.edu.LagouBean.print())"/>
		</aop:aspect>
	</aop:config>
public class LogUtils {
	public void beforeMethod() {
		System.out.println("前置通知");
	}
}

创建过程

在获取对象的地方,打一个断点,看下是否已经拿到代理对象。

image-20201103212537738


既然在容器启动过程,已经创建代理对象,那么我们不妨再思考下,根据spring bean的生命周期,哪个方法最合适创建对象??既然需要代理,那前提是有目标对象。我们知道在执行后置处理器的postProcessAfterIntialization()时,一个完整的对象实例已经创建完成,所以该方法是个合适的创建代理对象时机。

image-20201103213613063


    @Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		// getgetBeanPostProcessors():获取到多个后置处理器,我们需要找到与自动代理相关的AbstractAutoProxyCreator
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

由于ioc容器会有多个后置处理器,与Spring AOP相关的是AbstractAutoProxyCreator,继续往下执行,马上就能找到创建对象的方法。


	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
        // 获取该对象匹配的增强器
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 创建代理对象
            Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean方法中调用findEligibleAdvisors方法,获取增强器。

	@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
		// 获取对象匹配的增强器
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        // 获取所有增强器
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
        // 匹配目标类的增强器
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
            // 增强器排序
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

AbstractAutoProxyCreator#createProxy在这个方法里面,会创建一个代理工厂,进行一些配置

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		// 应该将增强器转换下类型
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    	// 将增强器和目标类注入到代理工程
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		// 至此,完成代理工厂的设置,开始创建代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}

public Object getProxy(@Nullable ClassLoader classLoader) {
		// 先创建AOP Proxy,再创建Proxy
		return createAopProxy().getProxy(classLoader);
	}

    @Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			// 目标对象是接口,或者目标对象是代理对象
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			// 使用cglib动态代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			// 使用jdk动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

由于LagouBean没有实现接口,所以通过cglib创建代理对象,在CglibAopProxy#getProxy截取部分代码,可以看到使用cglib创建代理对象。

image-20201103215244322


总结

跟着上面的步骤,我们看到了代理对象的创建过程。在spring启动过程中,首先创建目标对象,目标对象在执行init-method方法前后会被后置处理器拦截,其中AbstractAutoProxyCreator后置处理器会创建代理对象。过程是先获取目标类匹配到的增强器,接着创建一个代理工厂ProxyFactory,注入增强器和目标类。接着会根据目标对象是否实现接口、proxyTargetClass的属性值等判断条件,选择创建JDK还是CGLIB动态代理的AopProxy,最后调用对应的动态代理的方法创建代理代理对象

增强器:我的理解是横切时需要执行的代码和切入时机。

创建代理对象,可看成分为两步:先创建目标对象,再创建代理对象

创建目标对象:
          4)、finishBeanFactoryInitialization(beanFactory); 完成BeanFactory初始化工作,创建Bean对象
              1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
                  getBean->doGetBean()->getSingleton()->
              2)、创建bean
                  1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;
                  2)、createBean(); 创建bean;
			创建过程:执行构造函数 -> 属性设置 -> 各种xxxAware接口 -> beforeInit -> afterPropertySet -> init-method -> afterInit
--------------------------------------------------------------------------------------------------------------------------
创建代理对象
	1)、init-method执行前调用postProcessBeforeInstantiation();
         不做任何处理(spring 5.1.x)
              
 	2)、init-method执行后调用postProcessAfterInitialization();
          1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors
             1、找到候选的所有的增强器(增强器:找哪些通知方法是需要切入当前bean方法的)
             2、获取到能在bean使用的增强器。
             3、给增强器排序
         2)、保存当前bean在advisedBeans中;
         3)、如果当前bean需要增强,创建当前bean的代理对象;
             1)、获取所有增强器(通知方法)
             2)、保存到proxyFactory
             3)、创建代理对象:Spring自动决定
                 JdkDynamicAopProxy(config);jdk动态代理;
                 ObjenesisCglibAopProxy(config);cglib的动态代理;
         4)、给容器中返回当前组件使用cglib增强了的代理对象;
         5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;

获取拦截器链

接下来,我们继续分析目标方法被拦截并执行的过程。

因为需要跟踪目标方法执行过程,我们在目标方法处打一个断点,从这里逐步跟踪。

image-20201105213028709

image-20201105212945220

可以看到,此时的bean对象已经是由cglib创建的代理对象,我们一路debug,进入到DynamicAdvisedInterceptor#intercept方法,且慢,我们再回头看下,刚刚获取到的代理对象其中有个属性CGLIB$CALLBACK_0的值就是DynamicAdvisedInterceptor对象。

由于intercept方法内容比较多,直接说下过程,方法里面会获取目标方法的拦截链,接着创建MethodInvocation对象,并调用proceed方法,触发拦截器

image-20201105214102210

我们去瞧瞧ReflectiveMethodInvocation#proceed方法,里面有一个currentInterceptorIndex记录当前拦截器索引,当所有拦截器都执行完成,就调用连接点。

我们将分多次进入这个方法,更加直观感受这执行过程。。。


第一次进入,执行ExposeInvocationInterceptor#invoke。另外,我们可以看到interceptorsAndDynamicMethodMatchers 保存了所有拦截器,每次通过当前下标获取对应的拦截器。

image-20201105215033726

image-20201106101213525


第二次进入,执行MethodBeforeAdviceInterceptor#invoke方法 ,在方法体内,通过methodInvocation,再次调用proceed方法。image-20201105215210724

image-20201105215308770


第三次进入,执行CglibMethodInvocation#invokeJoinpoint,一路跟踪,最终执行连接点方法

image-20201105215729108

image-20201105215809626

image-20201105215825656


image-20201105220019733

根据以上的分析,我们可以知道,代理对象执行目标方法时,会被CglibAopProxy.intercept拦截,(DynamicAdvisedInterceptor是CglibAopProxy内部类)。

在intercept方法中,会获取到目标方法的拦截器链,接着创建一个CglibMethodInvocation对象,并调用proceed方法。在proceed方法中,会记录当前拦截器的索引,通过索引从匹配器列表获取到对应拦截器,接着调用拦截器实现的invoke方法,在invoke方法里面,还会继续调用MethodInvocation的proceed方法。再次进入proceed,重复之前的执行过程,直到所有拦截器执行完成,就调用连接点方法。

调用过程:CglibAopProxy.intercept -> methodInvocation -> proceed -> Intercept -> invoke
| _ _ _ _ _ _ _ _ _ _ _ |

初始入口:CglibAopProxy.intercept 创建的methodInvocation

循环结束:currentInterceptorIndex等于拦截器长度-1

3)、目标方法执行;容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
         1)、CglibAopProxy.intercept() ==== 》》》 拦截目标方法的执行
         2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
             1)、List<Object> interceptorList保存所有拦截器 5个
                 1个默认的ExposeInvocationInterceptor 和 4个增强器;
             2)、遍历所有的增强器,将其转为Interceptor;
                 registry.getInterceptors(advisor);
             3)、将增强器转为List<MethodInterceptor>;
                 如果是MethodInterceptor,直接加入到集合中
                 如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
                 转换完成返回MethodInterceptor数组;
			3)、如果没有拦截器链,直接执行目标方法;        
			4)、如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个CglibMethodInvocation 对象,
				并调用 Object retVal =  mi.proceed();
			5)、拦截器链的触发过程;        
				1)、如果没有拦截器则直接执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)就直接执行目标方法;        
				2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;           
					拦截器链的机制,保证通知方法与目标方法的执行顺序;

补充:刚刚我们使用的是CGLIB动态代理,如果使用JDK动态代理时,执行目标方法,会被JdkDynamicAopProxy#invoke拦截,执行过程和CglibAopProxy#intercept一样,都会先获取拦截器链,接着创建MethodInvocation对象,调用proceed方法。