Spring源码分析-04-AOP解析

image-20210420212916347

  • PS: 若文章字体偏大或者偏小,建议通过 ctrl键+鼠标滑轮 进行修改,以提升阅读效果.(带来不便,请谅解!)

Version:

  • jdk 1.8
  • Spring: 5.1.7

AOP使用流程:

  1. 导入aop 模块 spring-aop
  2. 定义业务逻辑类 MathCalculator: 定义了 除法div () .
  3. 定义切面类: LogAspects: 这里面定义了@PointCut切入点, @Before ,@After, @AfterReturn,@AfterThrowing 方法 .
  4. 定义了配置类MainConfigOfAOP. 开启AOP(@EnableAspectJAutoProxy)功能,并将MathCalculator,LogAspects 注入到 Spring中.

测试类:

main 方法:

	@Test
	public void test01(){
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
		
		//1、不要自己创建对象
//		MathCalculator mathCalculator = new MathCalculator();
//		mathCalculator.div(1, 1);
		MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
	 	 System.out.println(" ====================normal============== ");
        mathCalculator.div(4, 2);

        System.out.println(" ====================== error ============");

        mathCalculator.div(1, 0);
		
		applicationContext.close();
	}

配置类:

@EnableAspectJAutoProxy
@Configuration
//@ComponentScan("com.atguigu.bean")
public class MainConfigOfAOP {
	 
	//业务逻辑类加入容器中
	@Bean
	public MathCalculator calculator(){
		return new MathCalculator();
	}

	//切面类加入到容器中
	@Bean()
	public LogAspects logAspects(){
		return new LogAspects();
	}
}

业务类:

  • MathCaculator.java
public class MathCalculator {
	
	public int div(int i,int j){
		System.out.println("MathCalculator...div...");
		return i/j;	
	}

}

切面:

@Aspect
public class LogAspects {
   
   //抽取公共的切入点表达式
   //1、本类引用
   //2、其他的切面引用
   @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
   public void pointCut(){};
   
   //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
   @Before("pointCut()")
   public void logStart(JoinPoint joinPoint){
      Object[] args = joinPoint.getArgs();
      System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
   }
   
   @After("com.atguigu.aop.LogAspects.pointCut()")
   public void logEnd(JoinPoint joinPoint){
      System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
   }
   
   //JoinPoint一定要出现在参数表的第一位
   @AfterReturning(value="pointCut()",returning="result")
   public void logReturn(JoinPoint joinPoint,Object result){
      System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
   }
   
   @AfterThrowing(value="pointCut()",throwing="exception")
   public void logException(JoinPoint joinPoint,Exception exception){
      System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
   }

}

方法执行结果:

image-20210420161344165

人话描述过程:

AOP的开启过程:

注册Bean定义信息:

  • 堆栈信息图:

image-20210420130532493

有图可以知道 以下执行流程:

1. 注册BeanDefinition
AbstractApplicationContext.refresh()
    -> AbstractApplicationContext.invokeBeanFactoryPostProcessors() /// 注册 org.springframework.aop.config.internalAutoProxyCreator 的 BeanDefinition
    	->invokeBeanDefinitionRegistryPostPRocessors()
    	-> ...
    	-> AspectJAutoProxyRegistrar.registerBeanDefinitions() 

实例化 对象

  • AnnotationAwareAspectJAutoProxyCreator.class
    
    
    ![image-20210420132659526](/images/image-20210420132659526.png)
    
    ```java
     2. 生成实例对象
    AbstractApplicationContext.refresh()
        -> AbstractApplicationContext.invokeBeanFactoryPostProcessors() // 在这执行的原因 AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor 接口 
        	-> .....
        -> AbstractApplicationContext.registerBeanPostProcessors() /// 生成 internalAutoProxyCreator
        	-> doGetBean() 
        		->doCreatebean()

小总结:

  • @EnableAspectJAutoProxy
  1. 注册BeanDefinition 注册 org.springframework.aop.config.internalAutoProxyCreator 的bean定义信息

     **refresh()-> invokeBeanFactoryPostProcessors()** 
  2. 实例化对象: 实例化 org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator(原因 实现了BeanPostProcessor 接口)

      refresh() ->registerBeanPostProcessors()

AnnotationAwareAspectJAutoProxyCreator

PS: 源码分析 请点

代理对象生成流程:

就本方法而言, 就是 mathCalculator 对象生成过程.

堆栈信息图:

image-20210420154421955

具体堆栈信息:

AbstractApplicationContext.refresh()
    -> AbstractApplicationContext.finishBeanFactoryInitialization()
   		-> ...
    	-> AbstractBeanFactory.doGetBean()
    		-> AbstractAutowiredCapableBeanFactory.doCreateBean() 
    			->AbstractAutowiredCapableBeanFactory.initializatizeBean()
    				-> AbstractAutoProxyCreate.postProcessAfterInitialization()
    					-> AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean();// 获取所有的拦截器(Advisor)
    					-> AbstractAutoProxyCreator.wrapIfNecessary() // 判断是否需要增强当前bean
                            ->AbstractAutoProxyCreator.buildAdvisors();//构建当前bean的advisors 
    						->AbstractAutoProxyCreator.createProxy() // 创建代理对象
    							->DefaultAopProxyFactory.createProxy() //生成 cglib || jdk 类型的AopProxy
    								->CglibAopProxy.getProxy()// 生成代理对象 

源码分析 点击

代理对象方法执行:

即 mathCalculator.div() 方法

时序图:

image-20210420212916347

PS:许久未画时序图,图中表述可能存在错误,请见谅.

方法执行结果示图:

image-20210420161405473

根据测试结果图可知:

mathCalculator.div() 执行结果分为两种情况:

1.正常执行: @Before -> div() -> @After -> @AfterReturning

2.捕获异常: @Before-> div() -> @After -> AfterThrowing -> Exception

堆栈信息图:

image-20210420164052273

  • 由图可知, div 方法执行流程是 mathCalculator.div() -> CglibAopProxy.intercept()-ReflectiveMethodInvocation.proceed()

proceed() 执行堆栈信息

image-20210420165116058

  • 有图可知, **proceed()**默认执行是 :

    ExposeInvocationInterceptor.invoke() 
        ->AspectJAfterThrowingAdvice.invoke();//@AfterThrowing
    		->AfterReturningAdviceInterceptor.invoke(); //@AfterReturning
    			->AspectJAfterAdvice.invoke();	// @After
    				 ->MethodBeforeAdviceInterceptor.invoke()// @Before
                         ->MethodBeforeAdviceInterceptor.before()// 前置通知
                     ->MethodProxy.invoke()// 目标方法执行 invokeJoinpoint();
                ->invokeAdviceMethod(getJoinPointMatch(), null, null);// @After 执行 增强方法
    		-> advice.afterReturning(); //@AfterReturning 只有在不报异常的时候才执行(与@AfterThrowing 两选一个执行)
        ->  invokeAdviceMethod(getJoinPointMatch(), null, ex); //@AfterThrowing  执行异常 (与AfterReturning 二选一)

PS: 方法执行的具体源码分析请点这儿

源码分析:

开启AOP模块:

使用AspectJ 注解 :即使用@EnableAspectJAutoProxy

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

注册BeanDefinition

  • AspectJAutoPRoxyRegistrar.class
@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 注册aspectj注解自动代理创建器  即AnnotationAwareAspectJAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
		// 获取注解元信息 k-v map 存储
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {//设置属性, exposeProxy ,and proxyTargetClass
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {// 添加  proxyTargetClass 属性到 org.springframework.aop.config.internalAutoProxyCreator
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {// 添加  exposeProxy 属性到 org.springframework.aop.config.internalAutoProxyCreator
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}
  • AopConfigUtils.class
// 创建 或者升级 org.springframework.aop.config.internalAutoProxyCreator
	@Nullable
	private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		// 如果有 org.springframework.aop.config.internalAutoProxyCreator
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
				// 类加载顺序
				int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
				int requiredPriority = findPriorityForClass(cls);
				if (currentPriority < requiredPriority) {
					apcDefinition.setBeanClassName(cls.getName());
				}
			}
			return null;
		}
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); //cls:AspectJAnnotationAutoProxyCreator
		beanDefinition.setSource(source);
		beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
		beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

实例化对象

image-20210420132659526

由图可知, 实例化对象的过程在 refresh() -> registerBeanPostProcessors() -> doGetBean() -> doCreateBean() 方法 , 为Spring 创建对象的流程, 所以在此不做分析.

需要的小伙伴 可以查看:

生成代理对象:

跳过 Spring bean创建bean的( doGetBean()-> doCreateBean()-> initializeBean()->applyBeanPostProcessorsAfterInitialization())这些流程, 从 AbstractAutoProxyCreator.postProcessAfterInitialization() 方法开始分析.

AbstractAutoProxyCreator.java

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         return wrapIfNecessary(bean, beanName, cacheKey);// 判断当前类是否需要增强.
      }
   }
   return bean;
}
  • wrapIfNecessary() 判断当前类是否需要增强,若需要,则创建代理对象
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}//advisedBean中没有,则返回 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. //1. 找interceptors 拦截器
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		Object proxy = createProxy( // 2. 创建代理对象
				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}

	this.advisedBeans.put(cacheKey, Boolean.FALSE);
	return bean;
}
  • createProxy()
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
		@Nullable Object[] specificInterceptors, TargetSource targetSource) {
	// 1. 构建当前bean的proxyFactory
	ProxyFactory proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);
	// 2.根据beanName, 绑定对应的advisors   即 绑定 类与其对应的增强方法
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		//... .省略proxyFactory设置属性代码
       // 3获取代理对象
	return proxyFactory.getProxy(getProxyClassLoader());
}

ProxyFactory.java

public Object getProxy(@Nullable ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);// 
}

DefaultProxyFactory.java

  • 判断targetClass 类型,若是接口类型,则使用JDK代理,不是的话,则用 cglib代理
@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.");
      }// 判断 targetClass 是否是接口
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);// jdk proxy
      }
      return new ObjenesisCglibAopProxy(config);// cglib proxy
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

**PS: getProxy() 过程就不给出代码了, 有需要自己去看,在CglibAopProxy.getProxy() 以及JdkDynamicAopProxy.getProxy() **

目标方法执行:

流程:

1. 拦截目标方法
2.  调用methodInterceptor, 对目标方法进行增强

image-20210420213112210

拦截目标方法:

  • CglibAopProxy.class
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Object target = null;// 目标对象
			TargetSource targetSource = this.advised.getTargetSource();
			try {
				if (this.advised.exposeProxy) {
					// Make invocation available if necessary.
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
				target = targetSource.getTarget();// 获取目标类 targetClass
				Class<?> targetClass = (target != null ? target.getClass() : null);// 获取 拦截器链 Advisors 链
				List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
				Object retVal;//返回值
				// Check whether we only have one InvokerInterceptor: that is,
				// no real advice, but just reflective invocation of the target.
				if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {// 处理没有advisor 的 target
					// We can skip creating a MethodInvocation: just invoke the target directly.
					// Note that the final invoker must be an InvokerInterceptor, so we know
					// it does nothing but a reflective operation on the target, and no hot
					// swapping or fancy proxying.
					Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
					retVal = methodProxy.invoke(target, argsToUse);
				}
				else {// 拦截方法
					// We need to create a method invocation... 创建方法实现体, 并调用proceed() 
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null && !targetSource.isStatic()) {
					targetSource.releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

proceed()

  • 简单描述下proceed() 做的事情: 执行目标方法+增强方法

    • @Before -> 目标方法 -> @After ->@AfterReturning || @AfterThrowing 的顺序执行.
  • 源码的实现: 利用压栈(形成一条链)

    • 正序遍历 this.InterceptorsAndDynamicMethodMatchers,获取到每个方法拦截器 执行每个方法拦截器的invoke()方法,
      • 即按照 ExpostInvocationInterceptor -> @AfterThrowing -> @AfterReturing->@After-> @Before 顺序进行压栈, 然后执行methodProxy.invoke方法.然后依次返回, 依次调用各个方法拦截器 MethodInterceptor对应的方法.
  • image-20210420163857694

ReflectiveMethodInvocation.class

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.// this.currentInterceptorIndex =-1 (default)
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();// 执行目标方法
		}

		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

吐槽:

目标方法+ 方法 拦截器 的源码可阅读性有点差,不如改成for循环遍历的形式.(仅代表我自己的观点.)

总结:

  1. @EnableAspectJAutoProxy 注解开启:
    1. 注册beanDefinition : invokeBeanFactoryPostProcessors()
    2. 生成实例 : registerBeanPostProcessors()
  2. 目标对象生成:
    1. refresh() -> finishBeanFactoryInitialization()-> doGetBean()-> doCreateBean() -> initializeBean()->applyBeanPostProcessorAfterInitialization() -> postProcessorAfterInitialization()
    2. wrapIfNecessary() // 判断是否需要对Bean 对象进行增强, 即生成代理对象.
    3. getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// 获取增强方法,即拦截器链即Advisors
    4. buildAdvisors(beanName, specificInterceptors);// 将Advisors 与bean绑定
    5. createAopProxy(AdvisedSupport config)// 判断 代理方式 JDK || Cglib
    6. getProxy() // 生成代理对象
  3. 目标方法执行:
    1. 按照 @Before -> 目标方法 -> @After ->@AfterReturning || @AfterThrowing 的顺序执行.

参考: