框架源码专题:Spring的Aop实现原理,Spring AOP 与 AspectJ 的关系


1. Spring AOP 与 AspectJ 的关系

        Spring AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者增强处理。Aop依赖于IOC,Aop可以看做是调用IOC的后置处理器来实现的。 默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现。Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,这也是为什么我们不需要显式的引入这两个依赖。

         作为 Java 开发者,我们都很熟悉 AspectJ 这个词,甚至于我们提到 AOP 的时候,想到的往往就是 AspectJ,但真实情况是Spring虽然提供了AspectJ的支持,但只用到的AspectJ的切点解析和匹配。比如 @Aspect、@Pointcut、@Before、@After 、@Around 等注解都是来自于 AspectJ,利用AspectJ的解析execution、@Annotation等表达式的能力去解析,因为AspectJ也是一个优秀的框架,Spring为了不重复造轮子嘛,就利用到了这些。但是动态代理功能的实现是纯 Spring AOP 自己实现的。AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。

        在性能方面,由于Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。
        
Spring AOP术语解释

  • 切面(Aspect):横切业务代码,带有@Aspect注解的类,被称为切面类,用于存放不同的切点、通知方式(@Around)和切点逻辑等。
  • 连接点(Join point):在程序执行过程中某个特定的点,例如某个方法调用的时间点或者处理异常的时间点。
  • 通知(Advice): 前置通知@Before、后置@After、环绕@Around等等多种通知类型,不同的通知类型决定在不同的地方执行增强代码。 许多AOP框架,包括Spring在内,都是以拦截器做通知模型的,并维护着一个以连接点为中心的拦截器链。
  • 顾问(advisor):是Advice的一种包装,是Pointcut和Advice的一种结合!
  • 切点(Pointcut):类似于连接点,表示从哪个位置切入,一般与通知关联使用。
  • 织入(Weaving): 把通知逻辑切入连接点的过程
  • 引入(Introduction): 把其他接口和实现 动态的引入到目标类的过程

问题:为什么spring 不使用AspectJ全套的东西呢?而是只使用了部分呢?

猜测原因如下:

  • ①:AspectJ大部分内容是动态植入,因为AspectJ编译后的文件是.aj 结尾的,JVM编译后的是.class,如果spring使用AspectJ的动态植入,那么就要使用AspectJ的编译器,JVM是肯定编译不了的,无疑增加了开发成本!所以spring自己实现了一套代码实现植入增强!
  • ②:Spring在引入别的框架时,理念是取其精华、弃其糟粕。取Aspect对自己有用的理念和切点解析部分,舍弃掉了会增加开发成本的部分!


2. JDK和Cglib动态代理的区别

相同点

  • JDK动态代理和Cglib动态代理在 jdk1.7版本后都使用修改字节码的方式来进行代理。

不同点

  • ①:如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
  • ②:JDK动态代理类实现了InvocationHandler接口,重写的invoke方法。
  • ③:JDK动态代理的基础是反射机制(method.invoke(对象,参数))Proxy.newProxyInstance()
  • ④:如果目标对象没有实现接口,必须采用CGLIB,主要方式是对指定的类生成一个子类,覆盖其中的方法。Spring会自动在JDK动态代理和CGLIB之间转换。
  • ⑤:Cglib底层采用ASM字节码生成框架,使用字节码技术生成代理类。
  • ⑥:每一次jdk版本升级,jdk代理效率都得到提升,1.8版本已经略高于CGLIB代理
  • ⑦:Cglib会重复调用动态代理类,而JDK不会!!
代理类型JDKCglib
使用场景目标类实现了接口,且未指定ProxyTargetClass = true目标类未实现接口
代理类的字节码文件数量根据接口生成1个$proxy.class文件根据具体类生成多个cglib.class文件
调用 原始方法 的方式反射直接调用(正因为直接调用速度快,所以cglib在调用时比jdk快)
在被增强的方法中调用其他方法时其他方法不会被增强,动态代理类只调用一次其他方法会被增强,因为每一个方法都会调用动态代理类!
代码形式InvocationHandler.invokeMethodInterceptor.intercept


3. Spring AOP应用案例

@Aspect //切面
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DataSourceAspect {
    protected Logger logger = LoggerFactory.getLogger(getClass());
    
	//切入点,寻找带有@DataSource注解的方法
    @Pointcut("@annotation(com.chinalife.policy_manage.common.datasource.annotation.DataSource) " +
            "|| @within(com.chinalife.policy_manage.common.datasource.annotation.DataSource)")
    public void dataSourcePointCut() {

    }
    
	//环绕通知   ProceedingJoinPoint 连接点/切入点
    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
    	
        MethodSignature signature = (MethodSignature) point.getSignature();
        //获取目标类
        Class targetClass = point.getTarget().getClass();
        //获取目标方法
        Method method = signature.getMethod();

		//获取目标类上的@DataSource注解
        DataSource targetDataSource = (DataSource)targetClass.getAnnotation(DataSource.class);
        //获取目标方法上的@DataSource注解
        DataSource methodDataSource = method.getAnnotation(DataSource.class);

		//如果@DataSource注解不为空,执行增强逻辑
        if(targetDataSource != null || methodDataSource != null){
            String value;
            if(methodDataSource != null){
                value = methodDataSource.value();
            }else {
                value = targetDataSource.value();
            }

            DynamicContextHolder.push(value);
            logger.debug("set datasource is {}", value);
        }

        try {
            return point.proceed();
        } finally {
            DynamicContextHolder.poll();
            logger.debug("clean datasource");
        }
    }
}


4. Spring AOP有几种配置方式?

  • ①: Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的(如:MethodInterceptor、MethodBeforeAdvice)。
    • 实现MethodBeforeAdvice:≈ 前置通知
      public class LogAdvice implements MethodBeforeAdvice {
      
          @Override
          public void before(Method method, Object[] args, Object target) throws Throwable {
              String methodName = method.getName();
              System.out.println("执行目标方法【" + methodName + "】的<前置通知>,入参" + Arrays.asList(args));
          }
      }
      
    • 实现MethodInterceptor ≈ 环绕通知
      public class LogInterceptor implements MethodInterceptor {
          @Override
          public Object invoke(MethodInvocation invocation) throws Throwable {
              System.out.println(getClass()+"调用方法前");
              Object ret=invocation.proceed();
              System.out.println(getClass()+"调用方法后");
              return ret;
          }
      }
      
      然后把他们注册进容器中!即可实现增强逻辑,运行结果如下:
      在这里插入图片描述
             此中方法有个致命的问题,如果我们只能指定单一的Bean的AOP, 如果多个Bean需要创建多个ProxyFactoryBean 。而且,我们看到,我们的拦截器的粒度只控制到了类级别,类中所有的方法都进行了拦截。
              后来有了升级版,通过配置 Advisor(内部封装了Advice通知),精确定位到需要被拦截的方法,然后使用内部的 Advice 执行逻辑处理。
       @Bean 
       public NameMatchMethodPointcutAdvisor tulingLogAspect() { 
      	 NameMatchMethodPointcutAdvisor advisor=new NameMatchMethodPointcutAdvisor(); 
      	 // 通知(Advice) :是我们的通知类 
      	 // 通知者(Advisor):是经过包装后的细粒度控制方式。 
      	 advisor.setAdvice(tulingLogAdvice()); 
      	 advisor.setMappedNames("div"); 
      	 return advisor; 
       }
      
  • ②: Spring 2.0 XML 配置:Spring 2.0 以后使用 XML 的方式来配置,使用命名空间 ,主要是针对xml形式来配置!
  • ③:Spring 2.0 @AspectJ 配置:使用注解的方式来配置,这种方式感觉是最方便的,还有,这里虽然叫做 @AspectJ,但是这个和 AspectJ 其实没啥关系。


5. Spring AOP源码解析

Aop源码大概分为以下几步:

  1. spring boot 自动配置AopAutoConfiguration类中带有@EnableAspectJAutoProxy,项目启动即开启对spring AOP的支持,该注解注册了AnnotationAwareAspectJAutoProxyCreator类,该类实现了bean的后置处理器,可以在类创建过程中做一些其他操作
  2. 在bean后置处理器的postProcessBeforeInstantiation方法中,解析切面类,把通知封装成Advisor,并放入缓存advisorsCache中!
  3. 在创建每一个bean时,在bean的后置处理器中的postProcessAfterInitialization方法中,拿到缓存中所有的Advisor,根据切入点PointCut与当前bean做匹配,匹配成功与否决定是否需要创建动态代理!如果匹配到了,则根据实际情况创建动态代理
  4. 调用目标方法时,会调用经过动态代理增强的方法逻辑 !


5.1 自动配置类 AopAutoConfiguration 开启对Aop的支持

        在spring boot项目中,项目启动时会自动加载许多自动配置类,以完成项目结构!其中就有AopAutoConfiguration,该类的作用就是为项目提供Aop的支持,一种是jdk动态代理,一种是cglib动态代理

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
//自动配置类
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		//开启自动代理:@EnableAspectJAutoProxy
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
				
		//jdk动态代理
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
				
		//Cglib动态代理
		static class CglibAutoProxyConfiguration {
		
		}
	}

        可以看到自动配置类AopAutoConfiguration除了帮我们配置了jdk动态代理和cglib动态代理,还有一个注解@EnableAspectJAutoProxy,这个注解内部通过@Import导入了一个bean定义的注册器AspectJAutoProxyRegistrar

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class) //通过`@Import`导入了一个bean定义的注册器
public @interface EnableAspectJAutoProxy {

        这个注册器帮我们注册了一个Aop中非常重要的类AnnotationAwareAspectJAutoProxyCreator!该类实现了bean的后置处理器BeanPostProcessor,可以在类创建前后做一些操作,具体如下:

  • postProcessBeforeInstantiation方法中,解析切面类,把通知封装成Advisor,并放入缓存advisorsCache中!
  • postProcessAfterInitialization方法中,匹配切入点,创建动态代理
	@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		// 注册了一个Aop中非常重要的bean的后置处理器`AnnotationAwareAspectJAutoProxyCreator`!
		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

看一下AnnotationAwareAspectJAutoProxyCreator的继承关系:
在这里插入图片描述

        

5.2 解析切面类,封装成Advisor

        ①: 通过bean的后置处理器解析切面类,把通知封装成Advisor,并放入advisorsCache缓存中!
与spring事务一样,Aop也是通过bean的后置处理器解析带有@AspectJ的bean,这个bean的后置处理器在容器创建的时候就被注册,在解析时可以直接调用!

注意:下图中的AspectJAwareAdvisorAutoProxyCreator正是AnnotationAwareAspectJAutoProxyCreator的父类
在这里插入图片描述

Spring AOP发生在创建bean的时候,也就是finishBeanFactoryInitialization()内部的creatBean()方法中


	try {
		Object scopedInstance = scope.get(beanName, () -> {
			beforePrototypeCreation(beanName);
			try {
				//创建bean的方法
				return createBean(beanName, mbd, args);
			}
			finally {
				afterPrototypeCreation(beanName);
			}
		});
		bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
	}

        在creatBean()方法内部,resolveBeforeInstantiation方法会扫描@Aspect注解,解析切面类,把通知封装成Advisor,并放入缓存advisorsCache中!

	try {
	
		/**
		* 第一次调用bean的后置处理器,事务在这里不会被调用,aop的才会被调用
		* 为啥aop在这里调用了?因为在此处需要解析出对应的切面保存到缓存中
		*/
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}

进入resolveBeforeInstantiation方法:

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// 如果有bean后置处理器: InstantiationAwareBeanPostProcessors
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					//调用 postProcessBeforeInstantiation 方法
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						//调用 postProcessAfterInitialization 方法
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

        在实例化bean之前,会第一次调用bean的后置处理器,解析到所有的@AspectJ的类,保存到缓存中。那怎么解析的呢?进入上文resolveBeforeInstantiation方法中的applyBeanPostProcessorsBeforeInstantiation方法中!

	@Nullable
	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		/**
		 * 获取容器中的所有后置处理器
		 */
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			//判断后置处理器是不是InstantiationAwareBeanPostProcessor
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				//把我们的BeanPostProcessor强制转为InstantiationAwareBeanPostProcessor
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				/**
				 * 【很重要】
				 * 我们AOP @EnableAspectJAutoProxy 为我们容器中导入了 AnnotationAwareAspectJAutoProxyCreator
				 * 我们事务注解@EnableTransactionManagement 为我们的容器导入了 InfrastructureAdvisorAutoProxyCreator
				 * 都是实现了我们的 BeanPostProcessor接口,InstantiationAwareBeanPostProcessor,
				 * 进行后置处理解析切面
				 */
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		//构建我们的缓存key
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			//已经被解析过 直接返回
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			/**
			 * 判断是不是基础的bean
			 * 判断是不是应该跳过 (aop解析直接解析出我们的切面信息(并且把我们的切面信息进行保存),而事务在这里是不会解析的)
			 */
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

        由于AOP使用的是AnnotationAwareAspectJAutoProxyCreator类,所以选择这个类中的shouldSkip方法,在所有的bean定义中选择是否跳过,如果带有@AspectJ注解,就不跳过,把这个类中的带有@Before、@After、@Around等注解的方法封装成一个个Advisor(顾问),它是Pointcut和Advice的一种结合! 并添加进集合中

	@Override
	protected List<Advisor> findCandidateAdvisors() {
		//找出事务相关的advisor
		List<Advisor> advisors = super.findCandidateAdvisors();
		//找出Aspect相关的信息之后封装为一个advisor
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		//返回我们所有的通知
		return advisors;
	}

buildAspectJAdvisors方法内部会把带有下面的注解的挨个解析成Advisor

	//获取到切面类中的所有方法,但是该方法不会解析标注了@PointCut注解的方法
	for (Method method : getAdvisorMethods(aspectClass)) {
		//挨个去解析我们切面中的方法
		Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
		if (advisor != null) {
			advisors.add(advisor);
		}
	}

	//看是否含有这些注解!
	private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
			Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

把解析到的Advisor放入advisorsCache缓存中

	//加入到缓存中
	if (this.beanFactory.isSingleton(beanName)) {
		this.advisorsCache.put(beanName, classAdvisors);
	}

原理图:
在这里插入图片描述
注意:以上解析切面的操作,是在bean的第一个后置处理器postProcessBeforeInstantiation中完成的!


5.3 匹配并创建动态代理

② 根据 Advisor 中的 PointCut 决定当前bean是否创建动态代理

        我们都知道创建动态代理的时机是在初始化之后(如果存在循环依赖则在实例化之后!),所以在源码中创建动态代理在doCreateBean方法中的initializeBean方法中,这个方法内部调用了bean的后置处理器postProcessAfterInitialization,在后置处理器中完成了判断和动态代理的创建

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			//1.回调各种 Aware 接口
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//2.调用 BeanPostProcessorsBeforeInitialization 扩展
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//3.调用实现InitializingBean的afterPropertiesSet方法
			// 调用xml方式的 bean标签里配置init-mothod属性
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//4.调用 BeanPostProcessorsAfterInitialization 扩展,动态代理在这里!
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}


***********************************************************************************************
==================== applyBeanPostProcessorsAfterInitialization 内部创建动代理 ==================
***********************************************************************************************

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

		Object result = existingBean;
		
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			/** 【很重要】
			 * 我们AOP @EnableAspectJAutoProxy 为我们容器中导入了 AnnotationAwareAspectJAutoProxyCreator
			 * 我们事务注解@EnableTransactionManagement 为我们的容器导入了 InfrastructureAdvisorAutoProxyCreator
			 * 都是实现了我们的 BeanPostProcessor接口,InstantiationAwareBeanPostProcessor,
			 * 在这里实现的是BeanPostProcessor接口的postProcessAfterInitialization来生成我们的代理对象 */
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

AbstractAutoProxyCreator抽象类扩展了这个后置处理器

	/**
	 * 在该后置方法中 我们的事务和aop的代理对象都是在这生成的
	 * @param bean bean实例
	 * @param beanName bean的名称
	 * @return
	 * @throws BeansException
	 */
	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		if (bean != null) {
			//获取缓存key
			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;
		}
		//排除掉不需要增强的,比如Aop一些基础类
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		//是不是基础的bean 是不是需要跳过的
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		//***如果Advisor中的切点表达式命中了这个类,就返回适合本类的通知器Advisor!
		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;
	}

        其中getAdvicesAndAdvisorsForBean方法中拿到了所有的Advisor与当前bean进行了匹配,返回合适本类的通知器advisor,如果合适的advisor为空,则返回DO_NOT_PROXY,不需要代理,表示不需要代理。

	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
		/**
		 * 找到合适的增强器对象advisor
		 */
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		//若合适的通知器为空,则返回DO_NOT_PROXY,不需要代理
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	
		//找到ioc容器中候选的通知  (找到Aop扫描到所有通知的Advisor,注意是所有的!!!)
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		
		//判断我们的通知Advisor能不能作用到当前的类上,返回合适本类的通知器advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		
		//加了一个内置的advisor
		extendAdvisors(eligibleAdvisors);
		
		//对我们的advisor进行排序,如果有多个切面类,则根据order排序
		//排序方式:异常--返回通知--后置通知--前置通知
		//这样排序的原因是,后边调用目标方法会讲!!
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

findAdvisorsThatCanApply的调用链很深,这里就不再跟进了。

        以上代码其实都是匹配阶段的代码,如果匹配成功,则进入上文wrapIfNecessary方法中的createProxy方法中,开始真正创建动态代理对象

创建动态代理是在createProxy方法中由ProxyFactory代理工厂来创建的

	//创建一个代理对象工厂
	ProxyFactory proxyFactory = new ProxyFactory();
	
	。。。
	
	//真正的创建代理对象
	return proxyFactory.getProxy(getProxyClassLoader());

createAopProxy() : 该方法用来创建我们的代理对象

代理形式由ProxyTargetClass和是否实现接口来决定!!

  • ①:我们代理的类没有实现接口,那么会直接走cglib代理
  • ②:我们代理的类实现了接口,且ProxyTargetClass 指定为false才会走jdk动态代理,如果ProxyTargetClass指定的有值,则还是使用cglib代理
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		//判断我们是否前置指定使用cglib代理ProxyTargetClass =true  fasle
		//判断是否实现了接口
		//判断是否是Optimize() 可手动设置,一般为false
		//三个判断只要有一个是true,就会使用cglib动态代理!
		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是接口 使用的就是jdk代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			//cglib代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			//动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

至此,目标类的动态代理创建完成!


        

5.4 调用代理类增强逻辑

③ 调用目标方法

        如果使用的时jdk动态代理,在调用目标方法时会进入JdkDynamicAopProxy中的 invoke 方法,把通知加入责任链,把Advisor转换成Inteceptor,通过责任链的方式递归调用proceed()方法完成对方法的增强调用处理

	@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
		//获取到我们的目标对象
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			//若执行代理对象的equals方法不需要代理
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			//若执行的是hashCode方法 不需要代理
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			//若执行的class对象是DecoratingProxy 也不要拦截器执行
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			/**
			 * 这个配置很重要很实用【暴露我们的代理对象到线程变量中】需要搭配@EnableAspectJAutoProxy(exposeProxy = true)
			 * 一起使用.
			 * 比如我们的aop中 multi和 mode方法都是被切入的方法,但是在切入的方法中通过
			 * this来调用另外一个方法的时候,那么该方法就不会被代理执行,而是通过方法内部执行
			 *还有的就是事务方法调用事务方法的时候 也需要这样
			 */
			if (this.advised.exposeProxy) {
				//把我们的代理对象暴露到线程变量中
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			//获取我们的目标对象
			target = targetSource.getTarget();
			//获取我们目标对象的class
			Class<?> targetClass = (target != null ? target.getClass() : null);

			//把我们的aop的advisor 转化为拦截器,相当于责任链的Handler顶级接口
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			//加入我们的拦截器链为空
			if (chain.isEmpty()) {
				//通过反射直接调用执行
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				//创建一个方法调用对象
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				//调用执行,注意proceed方法是递归调用,
				//会把需要的通知 通过责任链模式全部调用
				retVal = invocation.proceed();
			}


			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
		
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

        注意:如果是jdk动态代理,在invoke方法中,会把代理对象暴露到本地线程变量ThreadLocal中,这样做的目的是:在A方法中调用另一个B方法时,保证两个方法都享受到动态代理的增强! 如果没有暴露出来,那么在调用B方法时,B方法是不会有增强逻辑的!而cglib就不存在这样的问题,因为他每次调用都会重新获取代理对象!

        把advisor转化为Inteceptor拦截器,用于责任链调用,这个拦截器就相当于责任链中的顶级接口Handler。然后递归调用proceed方法

	@Override
	@Nullable
	public Object proceed() throws Throwable {
		//执行到了最后一个拦截器的时候(从-1开始,结束条件执行目标方法是下标=拦截器的长度-1)
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			//如果责任链运行到了最后一个,表示增强代码结束,开始运行我们自己的代码逻辑
			return invokeJoinpoint();
		}

		/**
		 * 获取第一个方法拦截器,按照之前排好序的advisor获取 
		 * 顺序为:(新增的内置拦截器)-- 异常--返回通知--后置通知--前置通知
		 */
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				return proceed();
			}
		}
		else {
			//在这个地方需要注意,抵用第一个拦截器的invoke方法,传入的是this 当前的方法拦截器对象
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

问题:那么为什么之前要按照 异常–返回通知–后置通知–前置通知 的方式来排序呢?

        答:是因为在递归调用时,递的过程最底层的通知(前置通知)首先被执行,然后才会有归的过程。 所以为了使通知顺序保持 前置通知 – 目标方法 – 异常通知(如果有异常) – 返回通知 – 后置通知 的顺序,就必须按照这样排序!!

 

6. 五种通知执行顺序

 
6.1 目标方法无异常时

  • ①:前置通知
  • ②:环绕通知的调用目标方法之前的代码
  • ③:目标方法
  • ④:环绕通知的调用目标方法之后的代码
  • ⑤:返回通知
  • ⑥:后置通知

6.2 在目标方法抛出异常的情况下

  • ①:前置通知
  • ②:环绕通知的调用目标方法之前的代码
  • ③:目标方法 抛出异常 异常通知
  • ④:后置通知
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值