Spring AOP原理深度解析

参考:https://blog.csdn.net/woshilijiuyi/article/details/83934407

AOP使用

注解类 TimeLog

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeLog {

    String invokename() default "";

    String prefix() default "";
}

LogAspect 切面类

@Component
@Aspect
public class LogAspect {

    @Before("@annotation(TimeLog)")
    public void logBefore() {
        System.out.println("logBefore ~~~~~");
    }


    @After("@annotation(TimeLog)")
    public void logAfter() {
        System.out.println("logAfter ~~~~~");
    }

}

AopController 目标类

@Controller
public class AopController {

    @TimeLog(invokename = "AopController.requestTest", prefix = "requestTest")
    public void requestTest() {
        System.out.println("requestTest 启动~~");
    }
}

AopControllerTest 测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class AopControllerTest {

    @Test
    public void test() {
        ApplicationContext applicationContext = ApplicationContextHolder.getContext();
        AopController aopController = (AopController) applicationContext.getBean("aopController");

    }
}

Spring AOP核心类介绍

Spring AOP 多种代理机制相关核心类介绍
先介绍一些Spring Aop中一些核心类,大致分为三类:

advisorCreator,继承 spring ioc的扩展接口 beanPostProcessor,主要用来扫描获取 advisor。
advisor:顾问的意思,封装了spring aop中的切点和通知。
advice:通知,也就是aop中增强的方法。
对以上三类核心类对应的 UML 分别来看。

advisorCreator:
请添加图片描述

  • AnnotationAwareAspectJAutoProxyCreator:目前最常用的AOP使用方式。spring aop 开启注解方式之后,该类会扫描所有@Aspect()注释的类,生成对应的adviosr。目前SpringBoot框架中默认支持的方式,自动配置。
  • AbstractAutoProxyCreator:Spring 为Spring AOP 模块暴露的可扩展抽象类,也是 AOP 中最核心的抽象类。Nepxion Matrix 框架便是基于此类对AOP进行扩展和增强。
  • BeanNameAutoProxyCreator:根据指定名称创建代理对象(阿里大名鼎鼎的连接池框架druid也基于此类做了扩展)。通过设置 advisor,可以对指定的 beanName 进行代理。支持模糊匹配。
  • AbstractAdvisorAutoProxyCreator:功能比较强大,默认扫描所有Advisor的实现类。相对于根据Bean名称匹配,该类更加灵活。动态的匹配每一个类,判断是否可以被代理,并寻找合适的增强类,以及生成代理类。
  • DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默认实现类。可以单独使用,在框架中使用AOP,尽量不要手动创建此对象。
  • AspectJAwareAdvisorAutoProxyCreator:Aspectj的实现方式,也是Spring Aop中最常用的实现方式,如果用注解方式,则用其子类AnnotationAwareAspectJAutoProxyCreator。

advisor:
请添加图片描述

  • NameMatchMethodPointcut:名称匹配切面,通过指定方法集合变量mappedNames,模糊匹配。
  • NameMatchMethodPointcutAdvisor:方法名称切面顾问,内部封装了
    NameMatchMethodPointcut,通过设置方法名称模糊匹配规则和通知来实现切面功能。
  • RegexpMethodPointcutAdvisor:正则表达式切面顾问,可设置多个正则表达式规则,通过内部封装的
    JdkRegexpMethodPointcut解析正则表达式。
  • DefaultPointcutAdvisor:默认切面顾问,比较灵活。可自由组合切面和通知。
  • InstantiationModelAwarePointcutAdvisorImpl:springboot自动装配的顾问类型,也是最常用的一种顾问实现。在注解实现的切面中,所有@Aspect类,都会被解析成该对象。

advice:

请添加图片描述

AspectJMethodBeforeAdvice:前置通知,AspectJ中 before 属性对应的通知(@Before标注的方法会被解析成该通知),,在切面方法执行之前执行。
AspectJAfterReturningAdvice:后置通知,AspectJ中 afterReturning 属性对应的通知(@AfterReturning 标注的方法会被解析成该通知),在切面方法执行之后执行,如果有异常,则不执行。
注意:该通知与AspectJMethodBeforeAdvice对应。
AspectJAroundAdvice:环绕通知,AspectJ中 around 属性对应的通知(@Around标注的方法会被解析成该通知),在切面方法执行前后执行。
AspectJAfterAdvice:返回通知,AspectJ中 after 属性对应的通知(@After 标注的方法会被解析成该通知),不论是否异常都会执行。


大致流程主要分为三个步骤:
1: 创建AnnotationAwareAspectJAutoProxyCreator对象,继承 InstantiationAwareBeanPostProcessor,实例化前后的处理器。
2:通过 AnnotationAwareAspectJAutoProxyCreator 扫描容器中的切面,创建PointcutAdvisor对象
3:一般初始化Bean后,通过初始化前后的处理器通过生成代理类


AOP流程

分别来分析以上三个步骤。

1、创建 AnnotationAwareAspectJAutoProxyCreator 对象

SpringBootAOP同样以自动装配的方式使用插件,所以还是从 spring.factories入手, 这里是 SpringBoot 内置插件,从spring-boot-autoconfigure中的 spring.factories中查找aop自动配置类; 这里找到 AopAutoConfiguration

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
@Configuration(proxyBeanMethods = false)
//(1)这里 spring.aop.auto 默认为true ,并不需要手动开启,索引 springboot 主类不需要配置@EnableAspectJAutoProxy注解
@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(proxyTargetClass = false)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
                               matchIfMissing = false)
        static class JdkDynamicAutoProxyConfiguration {

        }

        @Configuration(proxyBeanMethods = false)
        @EnableAspectJAutoProxy(proxyTargetClass = true) // (2)proxyTargetClass 创建基于子类(CGlib)代理
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                               matchIfMissing = true)
        static class CglibAutoProxyConfiguration {

        }

    }

上述代码通过spring.aop.proxy-target-class变量来控制proxyTargetClass的变量,最终都会加载@EnableAspectJAutoProxy配置。
spring.aop.proxy-target-class默认为 true,该变量相当关键,控制 spring aop 代理类的生成方式。


继续跟踪注解@EnableAspectJAutoProxy

EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//导入配置类
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
	boolean proxyTargetClass() default false;
	boolean exposeProxy() default false;
}

AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
	 * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
	 * {@code @Configuration} class.
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 注入 AnnotationAwareAspectJAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			// 设置 aop 相关变量
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}
@Nullable
	public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
			@Nullable Object source) {

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
	}

上述代码可以看到注册了一个切面相关BeanDefinition,正是上面提到的类:
AnnotationAwareAspectJAutoProxyCreator,并设置了代理方式配置变量: proxyTargetClass,默认为true。

这里是创建了 AnnotationAwareAspectJAutoProxyCreatorBeanDefinition并没有实例化和初始化该对象。那什么时候会触发呢?

上面的 uml 图可以看到,该类继承的顶层接口为 BeanPostProcessor。我们知道BeanPostProcessor实现类会提前初始化,由PostProcessorRegistrationDelegate触发,具体细节之前博客有提到:
SpringBoot2 | @SpringBootApplication注解 自动化配置流程源码分析(三)

该类又继承BeanFactoryAware,所以在其在实例化 bean 后,会触发setBeanFactory()方法,最终会触发
initBeanFactory方法:

AnnotationAwareAspectJAutoProxyCreator#initBeanFactory

//初始化Bean工厂,用于创建Advisor
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    super.initBeanFactory(beanFactory);
    if (this.aspectJAdvisorFactory == null) {
        // advisor 工厂类
        this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
    }
    // 用于创建 advisor
    this.aspectJAdvisorsBuilder =
        new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

2、扫描容器中的切面,创建 PointcutAdvisor 对象

spring ioc流程加载的过程中,会触发 beanPostProcessor 扩展接口,
AnnotationAwareAspectJAutoProxyCreator又是SmartInstantiationAwareBeanPostProcessor的子类,所以该扩展接口正是 aop实现的入口。

这里触发AnnotationAwareAspectJAutoProxyCreator父类AbstractAutoProxyCreator.postProcessBeforeInstantiation()方法。

触发位置:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
	……
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
	……
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

AbstractAutoProxyCreator.postProcessBeforeInstantiation()

@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			//advisedBeans用于存储不可代理的bean,如果包含直接返回
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			//判定当前bean是否可被代理,不可代理,然后存入advisedBeans
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		//到这里,说明bean可以被代理,所以获取自定义目标类,没有则跳过
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			//获取所有的通知
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			//创建代理对象
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			//如果最终可以获得代理类,则返回代理类,直接执行实例化后置通知方法
			return proxy;
		}

		return null;
	}

来看一下判定 bean 是否被代理的方法依据:

@Override
protected boolean isInfrastructureClass(Class<?> beanClass) {
    return (super.isInfrastructureClass(beanClass) ||
            (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}
@Override
	public boolean isAspect(Class<?> clazz) {
		//如果有@Aspect注解,则不可被代理
		return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
	}
protected boolean isInfrastructureClass(Class<?> beanClass) {
    //判定当前bean是否是 Advice、Pointcut、Advisor、AopInfrastructureBean等子类或实现类,如果是,则不能被代理
    boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
        Pointcut.class.isAssignableFrom(beanClass) ||
            Advisor.class.isAssignableFrom(beanClass) ||
                AopInfrastructureBean.class.isAssignableFrom(beanClass);
    if (retVal && logger.isTraceEnabled()) {
        logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
    }
    return retVal;
}

重点来看 shouldSkip方法:

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    //获取所有的候选顾问类 advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor) {
            if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
                return true;
            }
        }
    }
    return super.shouldSkip(beanClass, beanName);
}

通过代码findCandidateAdvisors()方法获取所有候选的 advisor:

@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 获取Advisor 实现类,具体看以下截图......
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    // 将@Aspect注解类解析为advisor
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

advisors封装了切点和通知,如下

请添加图片描述

请添加图片描述

继续跟进buildAspectJAdvisors方法,会触发
ReflectiveAspectJAdvisorFactory中的getAdvisors方法:

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   //从 aspectMetadata 中获取 Aspect()标注的类 class对象
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    //获取Aspect()标注的类名
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
        new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    List<Advisor> advisors = new LinkedList<>();
    //遍历该类所有方法,根据方法判断是否能获取到对应 pointCut,如果有,则生成 advisor 对象
    for (Method method : getAdvisorMethods(aspectClass)) {
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    //获取 @DeclareParents 注解修饰的属性(并不常用)
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}

继续来看getAdvisor方法:

@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
                          int declarationOrderInAspect, String aspectName) {

    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    //根据候选方法名,来获取对应的 pointCut
    AspectJExpressionPointcut expressionPointcut = getPointcut(
        candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }
    //如果能获取到 pointCut,则将切点表达式 expressionPointcut、当前对象ReflectiveAspectJAdvisorFactory、 方法名等包装成 advisor 对象
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                                                          this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

继续跟踪getPointCut()方法中的 findAspectJannotationOnMethod

@SuppressWarnings("unchecked")
@Nullable
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
   //定义class对象数组,如果方法中有以下注解中任何一种,则返回该注解
   Class<?>[] classesToLookFor = new Class<?>[] {
         Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
   for (Class<?> c : classesToLookFor) {
      AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c);
      if (foundAnnotation != null) {
         return foundAnnotation;
      }
   }
   return null;
}

InstantiationModelAwarePointcutAdvisorImpl的构造方法会触发构造通知对象:

// 实例化advice
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
                                                         this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
                        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
	……
    AbstractAspectJAdvice springAdvice;
    //根据注解类型,匹配对应的通知类型
    switch (aspectJAnnotation.getAnnotationType()) {
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
            //最终通知
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
            //后置通知
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
            // 异常通知
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
            // 环绕通知
        case AtAround:
            springAdvice = new AspectJAroundAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
            //切面
        case AtPointcut:
            if (logger.isDebugEnabled()) {
                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
            }
            return null;
        default:
            throw new UnsupportedOperationException(
                "Unsupported advice type on method: " + candidateAdviceMethod);
    }
	……
    return springAdvice;
}

可以看到,根据@Aspect类中方法的注解类型,生成对应的advice,并通过通知的构造方法,将通知增强方法,切面表达式传入到通知当中。

到这里InstantiationModelAwarePointcutAdvisorImpl对象构造完毕。

3、生成代理

上面创建advisor的逻辑发生在扩展接口中的postProcessBeforeInstantiation,实例化之前执行,如果有自定义的TargetSource指定类,则则直接生成代理类,并直接执行初始化之后的方法postProcessAfterInitialization,这种情况使用不多(逻辑在 AbstractAutoPorxyCreator.postProcessBeforeInstantiation()方法中,上面2中查看);

常规代理类还是在postProcessAfterInitialization中创建,也就是 IOC 最后一个扩展方法(初始化Bean方法中)。

AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 这里触发 AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator.postProcessAfterinitialization方法;

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        //处理循环依赖的判断
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            // 如果有资格被代理,那就增强包装下
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }

   // 判断是否不应该代理这个bean
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   /*
    * 判断是否是一些InfrastructureClass或者是否应该跳过这个bean。
    * 所谓InfrastructureClass就是指Advice/PointCut/Advisor等接口的实现类。
    * shouldSkip默认实现为返回false,由于是protected方法,子类可以覆盖。
    */
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // 获取这个bean的advice
   // Create proxy if we have advice.
   //一会再讲,扫描所有的相关的方法(PointCut原始方法,哪些方法需要被代理)
   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,该方法最终会调用findEligibleAdvisors()Eligible意为有资格的,合适的。具体来看下:

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
   //查找有资格的advisor
   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();
   //这里会对获取的advisor进行筛选
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   //添加一个默认的advisor,执行时用到。
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      //设置排序
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

最终筛选会在AopUtils.findAdvisorsThatCanApply:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
   }
   List<Advisor> eligibleAdvisors = new LinkedList<>();
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
         eligibleAdvisors.add(candidate);
      }
   }
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      //调用 canApply 方法,遍历所有的方法进行匹配
      //调用canApply方法,遍历被代理类的所有的方法,跟进切面表达式进行匹配,如果有一个方法匹配到,也就意味着该类会被代理。
      //匹配方法是借助org.aspectj.weaver.internal.tools实现,也就是AspectJ框架中的工具类
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}

调用canApply方法,遍历被代理类的所有的方法,跟进切面表达式进行匹配,如果有一个方法匹配到,也就意味着该类会被代理。
匹配方法是借助org.aspectj.weaver.internal.tools实现,也就是AspectJ框架中的工具类,有兴趣的可以自行查看。

重点来看一下代理生成方式:

public Object getProxy(@Nullable ClassLoader classLoader) {
   //createAopProxy()创建 aop 代理,getProxy生成代理类
   return createAopProxy().getProxy(classLoader);
}

最终调用DefaultAopProxyFactory#createAopProxy() 选择使用Cglib还是Jdk类型的代理方法

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   // optimize: 官方文档翻译为设置代理是否应执行积极的优化,默认为false。
   // proxyTargetClass:这个在上面已经提到了,AopAutoConfiguration中指定,默认为true,也就是选择使用 cglib 代理。
   //        可以看到该变量和optimize意义一样,之所以这么做,个人理解是为了可以在不同的场景中使用。
   // hasNoUserSuppliedProxyInterfaces 是否设置了实现接口
   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.");
      }
      //如果代理目标是接口或者Proxy类型,则走jdk类型
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

上述方法通过三个变量来进行筛选代理方法:

**optimize:**官方文档翻译为设置代理是否应执行积极的优化,默认为false。
**proxyTargetClass:**这个在上面已经提到了,AopAutoConfiguration中指定,默认为true,也就是选择使用 cglib 代理。 可以看到该变量和optimize意义一样,之所以这么做,个人理解是为了可以在不同的场景中使用。
hasNoUserSuppliedProxyInterfaces:是否设置了实现接口。

private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
   Class<?>[] ifcs = config.getProxiedInterfaces();
   return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}

主要就是判断AdvisedSupport中interfaces变量中是否设置了接口,意思是如果一个类实现了接口,把接口设置到该方法的变量中,但是不是一定会设置到该变量中,具体设置接口的代码如下:

可以看到如果用默认配置也就是proxyTargetClass为true时,只有一种情况会走jdk代理方法,就是代理类为接口类型(注意:代理类是接口类型,并不是指接口类是否实现了接口)或者代理类是Proxy类型,否则全部走cglib代理。所以,平时使用中,代理类大部分还是用cglib的方式来生成。


Spring Boot 1.x 版本和 2.x版本 AOP 默认配置的变动

配置类AopAutoConfiguration:

1.5x版本:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
public static class CglibAutoProxyConfiguration {

}

2.x版本:

@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
                       matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {

}

@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true) // proxyTargetClass 创建基于子类(CGlib)代理
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                       matchIfMissing = true)
static class CglibAutoProxyConfiguration {

}

可以看到,在SpringBoot2.x中最主要的变化就是proxy-target-class默认为true,意味着类代理的时候全部走cglib代理方式,只有为接口代理时才走jdk代理(注意:这里为接口代理,不是指代理目标类是否实现了接口)。所以,在使用springboot2.x的版本中,除了代理目标类是接口外,其余的代理方式全部采用cglib类型。


SpringBoot 集成Mybatis 代理类如何生成的?

参考:https://www.cnblogs.com/youzhibing/p/10486307.html

解析@MapperScan或者@Mapper,存储入knowMappers中

Map<Class<?>, MapperProxyFactory<?>> knownMappers   //从中获取到mapper接口代理工厂类 

依赖注入Mapper类时,通过JDK方式生成代理类。 此代理类实现目标接口,和InvocationHandler, 执行代理类中增删改查,会调用MapperProxy中的invoke()方法。 执行后,解析唯一语句,处理缓存等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值