Código fuente Spring5 Análisis de código fuente 13-AOP (activado)

Bienvenidos a todos a prestar atención a  github.com/hsfxuebao  , espero que les sea útil. Si creen que es posible, hagan clic en Estrella.

1. Introducción y uso de Aop

Aop es 面向切面编程, y Aspect es una implementación de la idea de Aop. No todos los marcos AOP son iguales, pueden tener fortalezas y debilidades en el modelo de punto de unión, algunos permiten la notificación de aplicaciones en el nivel de modificador de campo y algunos solo admiten puntos de unión relacionados con la invocación de métodos. Spring 只支持方法级别的连接点Tenga en cuenta que

Spring proporciona 4 tipos de soporte AOP:

  • Spring Aop clásico basado en proxy
  • Corte Puro Pojo
  • @Aspect aspecto controlado por anotación
  • Aspectos inyectables Aspectj

Los tres primeros son todas variantes de la implementación de Spring AOP. Spring AOP se basa en proxies dinámicos, por lo que el soporte de Spring para AOP se limita a la intercepción de métodos.

Este artículo presentará el uso clásico de Aop ( ProxyFactoryBean) y los aspectos basados ​​en @Aspectanotaciones .

La comprensión personal de la diferencia entre los dos radica en AspectJ的代理模式: Las clases que analizan @Aspectlas anotaciones se encapsulan dinámicamente Advisor(consultores) de acuerdo con diferentes anotaciones en el método, que contienen los métodos correspondientes Advicey especificados 切点(la coincidencia del método pointcut aquí se basa en expresiones lógicas ) Vamos, y el SpringAop tradicional necesita escribir su propia lógica de juicio, de hecho, también puede escribir un juicio de expresión lógica, por lo que es lo mismo aquí, pero la implementación es diferente)

Spring AopAspectJLa relación entre y : AspectJ一套AOP框架, es una extensión de la sintaxis y la semántica del lenguaje Java, por lo que proporciona un conjunto de palabras clave, lo que significa que si no está instalado AspectJ, no se puede usar AspectJ. Cabe señalar aquí que la función AOP implementada por las @Aspectanotaciones el marco AspectJ mencionado anteriormente @AspectLa implementación subyacente de la función AOP implementada mediante anotaciones en Spring sigue siendo Spring Aop.

1.1 Primavera clásica Aop

1.1.1 Interpretación básica

Hay varias clases clave en el clásico Spring Aop

  • Advisor: Consultores, los consultores son otro aspecto que ofrece Spring. Se pueden completar funciones de tejido de sección más complejas. PointcutAdvisorEs un tipo de consultor que puede especificar puntos de entrada específicos. El consultor ha empaquetado la notificación y entretejerá los aspectos en diferentes puntos de entrada en diferentes momentos según los diferentes tipos de notificación. Las notificaciones y los asesores son puntos de mejora de la implementación de aspectos, incluidos Advicey Pointcut. Personalmente, creo que es la unidad más pequeña para que Spring AOP complete la acción de mejora.
  • Advice: Notificación, la notificación es un aspecto ( Aspect) proporcionado por Spring. Sin embargo, su función es demasiado simple, solo puede entretejer el aspecto en todos los métodos de destino de la clase de destino y no puede completar el entretejido de aspecto en el método de destino especificado. El consejo en realidad usa operaciones de aumento concretas, las operaciones reales después del tejido de aspectos. Pointcut: Información de pointcut, esto se utiliza principalmente para determinar dónde está el pointcut, es decir, dónde cortar.

AdvisorDos subinterfaces PointcutAdvisor:IntroductionAdvisor

IntroductionAdvisor与PointcutAdvisor 最本质上的区别就是,IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice。而不能像PointcutAdvisor那样,可以使用任何类型的Pointcut,以及几乎任何类型的Advice。

PointCutAdvisor接口 比较常用的两个实现类:

  • 根据切入点(主业务方法)名称织入切面NameMatchMethodPointCutAdvisor
  • 根据自定义的正则表达式织入切面RegexpMethodPointoutAdvisor

1.1.2 简单Demo

声明两个通知类型 。一个是 MethodBeforeAdvice ,一个是 AfterReturningAdvice,见名知意,一个在方法执行前调用,一个在方法执行后调用

@Component
public class DemoAfterReturnAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("DemoAfterReturnAdvice.afterReturning");
    }
}
复制代码
@Component
public class DemoBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("DemoBeforeAdvice.before");
    }
}
复制代码

被代理的目标类 DemoController:

public class DemoController {

    public void hello(String msg) {
        System.out.println("hello " + msg);
    }
}
复制代码

配置了将代理对象注入,这里可以看到注入的是ProxyFactoryBean 。我们知道FactoryBean会将 getObject 方法的返回值作为结果注入到Spring容器中。这里不难猜测,ProxyFactoryBeangetObject 方法中必定做了代理。

@Configuration
public class AopConfig {

    @Bean("demoController")
    public ProxyFactoryBean proxyFactoryBean() {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        // 设置代理的目标类
        proxyFactoryBean.setTarget(new DemoController());
        // 设置通知拦截器
        proxyFactoryBean.setInterceptorNames("demoAfterReturnAdvice", "demoBeforeAdvice");
        return proxyFactoryBean;
    }
}
复制代码

我们来调用试试:

@SpringBootApplication
public class AopDemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(AopDemoApplication.class, args);
        DemoController demoController = (DemoController) run.getBean("demoController");
        demoController.hello("123");
    }
}
复制代码

输出结果如下: imagen.png

综上:可以看到 经典Spring AOP 起了作用。 核心逻辑就是在 ProxyFactoryBean 中的getObject方法中。

@Override
@Nullable
public Object getObject() throws BeansException {
        // 初始化连接器链路
        initializeAdvisorChain();
        if (isSingleton()) {
                // 获取代理类
                return getSingletonInstance();
        }
        else {
                if (this.targetName == null) {
                        logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
                                        "Enable prototype proxies by setting the 'targetName' property.");
                }
                return newPrototypeInstance();
        }
}
复制代码

主要步骤:

  1. 在getObject时会调用 initializeAdvisorChain() 根据InterceptorNames来初始化拦截器。
  2. 将拦截器包装成Advisor。(目前看来, Spring AOP一个增强功能最基本的实现单元就是Advisor)
  3. Advisor保存到this.advisors 集合中
  4. newPrototypeInstance();创建代理对象。这里的创建逻辑和@Aspect注解的AOP 实现逻辑基本相同(毕竟@Aspect使用的就是Spring AOP实现的) 5.根据某些条件选择cglib(CglibAopProxy)或者jdk(JdkDynamicAopProxy)代理方式。

关于详细的代码解读,后续会有文章进行解读。

1.2 @Aspect注解驱动的切面

  • 切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。
  • 连接点(Joinpoint) :程序执行过程中的某一行为。
  • 通知(Advice) :“切面”对于某个“连接点”所产生的动作。
  • 切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。
  • 目标对象(Target Object) :被一个或者多个切面所通知的对象。 AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。

1.2.1 定义切点

Spring 借助 AspectJ 的切点表达式语言来定义 Spring 切面

下面是用来定义切点的的描述符:

AspectJ指示器 描述
arg() 限制连接点匹配参数为指定类型的执行方法
@args() 限制连接点匹配参数由指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配 AOP代理的bean引用为指定类型的类
target 限制连接点匹配的目标对象为指定类型的类
@target() 限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类型的注解
within() 限制连接点匹配指定的类型
@within() 限制连接匹配指定注解所标注的类型(当使用 Spring Aop 时,方法定义在由指定的注解所标注的类里)
@annotation 限定匹配带有指定注解的连接点
bean() 限定 bean 的id

上述指示器中,只有 execution() 指示器是实际匹配执行的,其余都是限制匹配的。

execution (* com.kingfish.AopTest.test(..) && within(com.kingfish.AopTest.*))
复制代码

其中,使用execution() 执行器,选择了 com.kingfish.AopTest.test() 作为切点, * 代表这个方法可以返回任意类型。 .. 代表 这个方法可以使用任意参数。&& 代表与,也可以使用 and(与之类似的还有 || 代表或(or)、!代表非( not )。注意在xml配置中因为 & 具有其他含义,所以可以使用and代替&&) ,within() 代表 连接的一个操作。 within(com.kingfish.AopTest.*) 代表 com.kingfish.AopTest 类 的任意方法被调用。即这个切点的整个意义是, com.kingfish.AopTest.test方法被调用(这个方法可以传递任意参数,也可返回任意类型的返回值) 并且 com.kingfish.AopTest的任意方法被调用。

execution (* com.kingfish.AopTest.test(..) && bean('aop'))
复制代码

这个切点的整个意义是, com.kingfish.AopTest.test方法被调用(这个方法可以传递任意参数,也可返回任意类型的返回值)但限定bean的Id为 aop

1.2.2 定义切面

Spring 使用 AspectJ 注解来声明通知方法:

注解 通知
@After 通知方法会在目标方法返回或抛出异常后调用
@AfterReturning 通知方法会在目标方法返回后调用
@AfterThrowing 通知方法会在目标方法抛出异常后调用
@Around 通知方法会将目标方法封装起来,环绕通知方式(后续实例中讲解)
@Before 通知方法会在目标方法调用之前执行

1.3 代码实践

上面说的很混乱,如果没有代码对没有接触的过的人不好理解,这里通过代码来进行进一步的分析.

引入依赖:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.5</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.9</version>
</dependency>
复制代码

实体类:

@Component  //切面存在的化就会返回代理对象
public class HelloService {

   public HelloService(){
      System.out.println("....");
   }

   public String sayHello(String name){
      String result = "你好:"+name;
      System.out.println(result);
      int length = name.length();
      return result + "---" + length;
   }
}
复制代码

编写切面类并定义切点:

/**
 * Spring5以后顺序就一切正常
 * 正常:前置通知===目标方法===返回通知===后置通知
 * 异常: 前置通知===目标方法===异常通知===后置通知
 * try{
 *     前置通知
 *     目标方法的执行
 *     返回通知
 * }catch(){
 *     异常通知
 * }finally{
 *     后置通知
 * }
 */
@Component  //切面也是容器中的组件
@Aspect //说明这是切面
public class LogAspect {

   public LogAspect(){
      System.out.println("LogAspect...");
   }

   //前置通知  增强方法/增强器
   @Before("execution(* com.hsf.spring.aop.HelloService.sayHello(..))")
   public void logStart(JoinPoint joinPoint){
      String name = joinPoint.getSignature().getName();
      System.out.println("logStart()==>"+name+"....【args: "+ Arrays.asList(joinPoint.getArgs()) +"】");
   }

   //返回通知
   @AfterReturning(value = "execution(* com.hsf.spring.aop.HelloService.sayHello(..))",returning = "result")
   public void logReturn(JoinPoint joinPoint,Object result){
      String name = joinPoint.getSignature().getName();
      System.out.println("logReturn()==>"+name+"....【args: "+ Arrays.asList(joinPoint.getArgs()) +"】【result: "+result+"】");
   }


   //后置通知
   @After("execution(* com.hsf.spring.aop.HelloService.sayHello(..))")
   public void logEnd(JoinPoint joinPoint){
      String name = joinPoint.getSignature().getName();
      System.out.println("logEnd()==>"+name+"....【args: "+ Arrays.asList(joinPoint.getArgs()) +"】");
   }


   //异常
   @AfterThrowing(value = "execution(* com.hsf.spring.aop.HelloService.sayHello(..))",throwing = "e")
   public void logError(JoinPoint joinPoint,Exception e){
      String name = joinPoint.getSignature().getName();
      System.out.println("logError()==>"+name+"....【args: "+ Arrays.asList(joinPoint.getArgs()) +"】【exception: "+e+"】");
   }
}
复制代码

配置类中 开启 AspectJ 代理:

@Configuration
//@Import({Person.class}) // 导入某个bean,默认使用无参构造器创建对象
//@Import(value = {MainConfig.MyImportBeanDefinitionRegistrar.class})
@ComponentScan("com.hsf.spring")  // 默认扫描当前路径下的bean
@EnableAspectJAutoProxy
public class MainConfig {
   @Bean
   public Person getPerson() {
      Person person = new Person();
      person.setName("张三");
      return person;
   }
}
复制代码

测试类:

public class AnnotationMainTest {
   public static void main(String[] args) {

      AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(MainConfig.class);

      //AOP,原理测试
      HelloService helloService = context.getBean(HelloService.class);
      helloService.sayHello("zhangsan");
    }
}
复制代码

运行结果如下:

logStart()==>sayHello....【args: [zhangsan]】
你好:zhangsan
logReturn()==>sayHello....【args: [zhangsan]】【result: 你好:zhangsan---8】
logEnd()==>sayHello....【args: [zhangsan]复制代码

环绕通知的使用:在上面的Demo基础上,我们来看看环绕通知的使用。我们需要继续编写 AopDemo类。仅需在 AopDemo 中添加如下方法

@Around("execution(* com.hsf.spring.aop.HelloService.sayHello(..))")
public void around(ProceedingJoinPoint joinPoint) {
   System.out.println("around start");
   try {
      System.out.println("around before");
      joinPoint.proceed();    // 放行切点的方法,不放行则会阻塞调用
      System.out.println("around after");
   } catch (Throwable throwable) {
      throwable.printStackTrace();
      System.out.println("around throwable");
   }

}
复制代码

测试结果可以看到如下:

around start
around before
logStart()==>sayHello....【args: [zhangsan]】
你好:zhangsan
logReturn()==>sayHello....【args: [zhangsan]】【result: 你好:zhangsan---8】
logEnd()==>sayHello....【args: [zhangsan]】
around after
复制代码

1.4 MethodInterceptor和HandlerInterceptor区别:

  • HandlerInterceptor :是Spring mvc提供的拦截器,这种拦截器的生效时机实在DispatcherServlet分发请求时生效。并非是依赖于SpringAOP功能。正因如此,是只能拦截Controller层的方法请求。使用时需要重写WebMvcConfigurerAdapter.addInterceptors方法,来添加指定的拦截器。

  • org.springframework.cglib.proxy.MethodInterceptor :这个是 Cglib 进行代理时所使用的拦截器。

  • org.aopalliance.intercept.MethodInterceptor :就是利用Spring AOP生成的拦截器。所以实际上MethodInterceptor的实现也就是Spring Aop的实现,和之前写的ProxyFactoryBean的用法相同,可以拦截所有层面的方法。其实现也继承了 Advice 接口,结构如下: imagen.png

2. AOP注入了那些组件?@EnableAspectJAutoProxy

在使用AspectJ AOP 功能时,我们需要使用注解 @EnableAspectJAutoProxy 来开启Aop 功能。那么我们的分析入口自然是从这个注解开始。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   // 是否代理目标对象:即是否使用cglib 代理
   boolean proxyTargetClass() default false;
   
   // 是否暴露代理对象
   boolean exposeProxy() default false;
}
复制代码

分析了这么久的源码,从上面我们可以看到 @EnableAspectJAutoProxy 注解 中使用了 @Import(AspectJAutoProxyRegistrar.class) 注解引入了AspectJAutoProxyRegistrar 类,因此我们下面来看看 AspectJAutoProxyRegistrar 类的实现。其继承图: imagen.png

AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,那么我们自然要看看他的registerBeanDefinitions 方法了,registerBeanDefinitions 方法的作用是在Spring进入下一步动作之前可以添加BeanDefinition,而Spring Aop 在这里将会将自动代理创建器 AbstractAutoProxyCreator添加到Spring容器中,AbstractAutoProxyCreator 是Spring 实现Aop的核心类。(Spring 在 ConfigurationClassPostProcessor 中完成了对 ImportBeanDefinitionRegistrar 接口的处理,主要功能还是将BeanDefinition保存,等待Spring解析加载到容器中。

我们直接看核心registerBeanDefinitions方法:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

   @Override
   public void registerBeanDefinitions(
         AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

      // 如有必要,注册Aspect J注释自动代理创建器。这里注册的自动代理创建器Aop 实现的核心
      // 这里之所以说如有必要,是因为在调用该方法时,容器中可能已经创建了一个自动代理创建器,
      // 如果这个自动代理创建器优先级更高或者与当前需要创建的自动代理创建器是同一类型,则不需要创建。

      // 注册切面的基于注解的自动代理创建器
      AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

      // 获取 @EnableAspectJAutoProxy 注解
      AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
      if (enableAspectJAutoProxy != null) {
         // 解析 proxyTargetClass 属性
         if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
         }
         //  解析 exposeProxy 属性
         if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
         }
      }
   }

}
复制代码

从上面代码我们可以看到,registerBeanDefinitions 方法最主要的功能就是自动代理创建器的注册。(所谓的自动代理创建器,顾名思义就是可以用来自动创建代理的"机器",可以简单理解成Spring 封装的一个创建代理对象的工具类,具有多种实现方式,这个下面会讲。这里使用AOP的实现方式,因此我们来看他的注册过程, 即 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 方法 。

其中 registerAspectJAnnotationAutoProxyCreatorIfNecessary 方法在经历数次跳转后最终调用了 AopConfigUtils#registerOrEscalateApcAsRequired 方法。

// 保存候选的自动代理创建器集合。
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

static {
   // Set up the escalation list...
   // 这里面三种都是 自动代理创建器,会根据情况选择一个自动代理创建器加载。
   // 需要注意的是,自动代理创建器只能加载一种,若已经加载一种,则会根据优先级选择优先级高的重新加载
   // 事务使用
   APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
   APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
   APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}

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

   // 注册AnnotationAwareAspectJAutoProxyCreator 后置处理器组件
   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

// 这里的 cls 是 AnnotationAwareAspectJAutoProxyCreator.class
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
      Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

   // 如果有注册,则判断优先级,将优先级的高的保存
   // 如果已经存在了自动代理创建器,且存在的自动代理创建器与现在的并不一致,那么需要根据优先级来判断到底要使用哪个
   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) {
            // 改变bean所对应的className 属性
            apcDefinition.setBeanClassName(cls.getName());
         }
      }
      // 如果已经存在自动代理创建器,并且与将要创建的一致,那么无需再次创建
      return null;
   }

   RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
   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;
}

// 可以看到,所谓的优先级顺序实际上是在 APC_PRIORITY_LIST 集合的顺序
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      // 设置 proxyTargetClass 属性
      definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
   }
}

public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      // 设置 exposeProxy 属性
      definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
   }
}
复制代码

这里可以看到,整体是注册了一个beanName为“org.springframework.aop.config.internalAutoProxyCreator” 的bean,在 AOP 场景下,Bean 类型为 AnnotationAwareAspectJAutoProxyCreator。到这里我们就可以知道Aop的功能完成肯定是在 AnnotationAwareAspectJAutoProxyCreator 中完成的,其实他是 SmartInstantiationAwareBeanPostProcessor,继承图如下:

imagen.png 说明:

  • 这里之所以 beanName (AUTO_PROXY_CREATOR_BEAN_NAME) 和 bean的类型并不相同,是因为这个beanName 特指内部的自动代理创建器,但是自动创建代理器会对应多种不同的实现方式。比如在默认的事务中,注入的bean类型却为InfrastructureAdvisorAutoProxyCreator,而AOP的实现却是 AnnotationAwareAspectJAutoProxyCreator。之所以注册不同是因为实现功能上的区别。对于事务的自动代理创建器来说,他只需要扫描被事务注解修饰的方法,并进行代理。而Spring Aop 则需要根据 @PointCut 注解 来动态的解析代理哪些方法。

  • 关于优先级的问题,我们可以看到APC_PRIORITY_LIST 集合的顺序,下标越大,优先级越高。因此可以得知优先级的顺序应该是 InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator

2.1 AnnotationAwareAspectJAutoProxyCreator

由于本文主要分析的是 Spring Aop 的过程,所以我们下面还是对 AnnotationAwareAspectJAutoProxyCreator 自动代理创建器进行分析。AnnotationAwareAspectJAutoProxyCreator 本身的逻辑并不多,核心逻辑在其父类AbstractAutoProxyCreator 中。

上面我们可以看到,整个过程就是将 AnnotationAwareAspectJAutoProxyCreator 注册到 Spring 中并且设置一些属性。

那么我们来看看 AnnotationAwareAspectJAutoProxyCreator ,其主要逻辑实际上还是在其父类 AbstractAutoProxyCreator 中完成。(包括事务的实现逻辑也主要在 AbstractAutoProxyCreator 中,后续关于事务的源码分析)。

AnnotationAwareAspectJAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor接口的方法,SmartInstantiationAwareBeanPostProcessor 接口方法穿插在 Bean初始化的过程中,转念一想,Spring Aop的核心思想就是动态代理,那么必然会在bean初始化的时候"做手脚"。因此我们下面的重心就放在 SmartInstantiationAwareBeanPostProcessor 的方法分析上。

关于 后处理器SmartInstantiationAwareBeanPostProcessor 的内容 具体请参考Spring5源码5-Bean生命周期后置处理器

上面也说了,其主要逻辑在AbstractAutoProxyCreator 中实现,这里是在AbstractAutoProxyCreator 中实现的 SmartInstantiationAwareBeanPostProcessor 方法,所以我们下面看的实际是 AbstractAutoProxyCreator 类。

2.2 AbstractAutoProxyCreator

这里额外提一下,Spring事务的实现也依赖于 AbstractAutoProxyCreator 类,并且逻辑与Aop 的实现基本一致,因为事务的实现的方式也是Aop代理。

下面是AbstractAutoProxyCreatorSmartInstantiationAwareBeanPostProcessor 的一些实现方法的实现

@Override
@Nullable
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
        // 从代理缓存中获取代理类型
        if (this.proxyTypes.isEmpty()) {
                return null;
        }
        Object cacheKey = getCacheKey(beanClass, beanName);
        return this.proxyTypes.get(cacheKey);
}

@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
        return null;
}

@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
}

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

        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
                if (this.advisedBeans.containsKey(cacheKey)) {
                        return null;
                }
                // 是基础设施类 || 是被 @Aspect 注解修饰的类。则跳过 Aop代理
                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.
        // 正常来说Aop 的代理创建应当在Bean 创建后再进行代理类,但是这里在Bean创建前就可能进行了代理:
        // 对此,官方注释解释: 如果我们有自定义的TargetSource,请在此处创建代理。抑制目标Bean的不必要的默认实例化:TargetSource将以自定义方式处理目标实例。
        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;
}

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
        return true;
}

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        return pvs;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
}

/**
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@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;
}
复制代码

我们可以根据 SmartInstantiationAwareBeanPostProcessor 方法的调用顺序进行分析。如果想要生成代理,可以在bean初始化之后进行代理,也就是 postProcessBeforeInstantiation 方法中。但是在此之前,需要先判断一下当前bean是否需要代理,而这个判断应该在Bean 创建之前进行,即在 postProcessBeforeInstantiation 方法中。我们可以看到关键方法是在于 wrapIfNecessary

不过在此之前我们先来看看 postProcessBeforeInstantiation方法中的一段分析。

2.2.1 postProcessBeforeInstantiation

1. 是否跳过代理

实际上,并非所有满足织入条件的Bean 都会被代理。基础设施类无法代理,自身也无法代理自身。

我们这一部分主要是用来分析AbstractAutoProxyCreator#postProcessBeforeInstantiation 中的这一段代码:

// 是基础设施类 || 是被 @Aspect 注解修饰的类。则跳过 Aop代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return null;
}
复制代码

这段代码将在bean加载前判断bean是否交由Aop代理,亦或者换一种说法 : 判断将该Bean交由Spring容器创建还是交由Aop 创建。在实际创建bean代理时候,Spring会根据cacheKey 获取到值,为false则不需要代理。

我们可以看到关键的判断条件就是下面两个:

1.1. isInfrastructureClass(beanClass)

这里我们可以很清楚的看到,如果当前bean是基础类(Advice、Pointcut、Advisor、AopInfrastructureBean及其子类),则返回true。

protected boolean isInfrastructureClass(Class<?> beanClass) {
        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;
}
复制代码
1.2. shouldSkip(beanClass, beanName)

AspectJAwareAdvisorAutoProxyCreator#shouldSkip:

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        // TODO: Consider optimization by caching the list of the aspect names
        // 寻找所有候选代理增强点。关于这个方法,在后面关于 getAdvicesAndAdvisorsForBean 的文章中会详细分析,这里就不分析
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        for (Advisor advisor : candidateAdvisors) {
                // 从前面的代码分析可以看出,如果是Aop 的动态封装都是基于 InstantiationModelAwarePointcutAdvisorImpl 也就是 InstantiationModelAwarePointcutAdvisor,自然是继承PointcutAdvisor
                // 如果 代理类基于 AspectJPointcutAdvisor  && aspectName==beanName,即当前初始化的类是ApspectJ类本身。则返回true,跳过代理
                if (advisor instanceof AspectJPointcutAdvisor &&
                                ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
                        return true;
                }
        }
        // 父类shouldSkip 判断了文件是否是 .ORIGINAL 后缀,是则跳过。
        return super.shouldSkip(beanClass, beanName);
}
复制代码

关于if语句判断条件:

  • advisor instanceof AspectJPointcutAdvisor :在 第1小节中我们说过,Advisor两个子接口PointcutAdvisor、IntroductionAdvisor 。IntroductionAdvisor与PointcutAdvisor 最本质上的区别就是,IntroductionAdvisor只能应用于类级别的拦截,只能使用Introduction型的Advice。而不能像PointcutAdvisor那样,可以使用任何类型的Pointcut,以及几乎任何类型的Advice。

    • 而通过 Spring Aop 动态注入的是 Advisor 默认都是 InstantiationModelAwarePointcutAdvisorImpl 都满此条件。所以这里为false 的情况只有硬编码注入时IntroductionAdvisor 类型的 Advisor ,所以这里基本都会返回true。
  • ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) : 这里就是判断beanName 是否是 @Aspect 注解修饰的bean的name。即自身不能代理自身。

综上,跳过Aop代理的条件就是:Aop基础设施类或者 代理自身时 会跳过代理

2.2.2 AbstractAutoProxyCreator#wrapIfNecessary

上面一步是强行跳过了一部分不能代理的Bean,如果到达这一步说明当前Bean不需要跳过代理,那么则需要判断当前Bean是否满足代理条件。

postProcessAfterInitialization 方法中我们可看到关键方法 wrapIfNecessarywrapIfNecessary 主要是用来判断当前bean是否需要代理,如果需要,则进行bean封装。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 如果当前bean已经处理过了直接返回
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
                return bean;
        }
        // 无需增强。这个在AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法中对 cacheKey 进行了判断缓存,this.advisedBeans.get(cacheKey) 的返回值代表当前bean是否需要aop代理。
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
                return bean;
        }
        // 给定的bean类是否是一个基础设施类(Advice、Pointcut、Advisor、AopInfrastructureBean) || 配置了指定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);
        // DO_NOT_PROXY = null。很明显,即使当前Bean 需要进行代理,如果没有增强方法也没必要进行代理
        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;
}
复制代码

可以很明显的发现下面两个方法是关键。

// 获取适配的增强点
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 根据增强点创建对象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
复制代码

需要注意的是,上面两句关键语句,在 AbstractAutoProxyCreator#postProcessBeforeInstantiation 中也有过调用。

3. 获取代理增强点 - getAdvicesAndAdvisorsForBean

主要是讲述 在 Bean创建过程中Aop 挑选适用于当前Bean的增强Advisor。准备用于代理使用

getAdvicesAndAdvisorsForBean 的实现在 AbstractAdvisorAutoProxyCreator 类中。getAdvicesAndAdvisorsForBean 的作用是获取所有适用于当前Bean 的 Advisors 。因为并不是所有的规则都适用于当前bean,所有会有一个筛选的过程。

这个方法的逻辑分为两步:

  • 寻找所有的顾问(Advisors), 这个方法在 AnnotationAwareAspectJAutoProxyCreator 中被重写了,为了可以的动态生成 AdvisorfindCandidateAdvisors
  • 寻找所有顾问(Advisors) 中适用于当前 bean 的增强并应用findAdvisorsThatCanApply
    下面我们来看详细代码:
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
                Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        // 主要逻辑还是在 findEligibleAdvisors 中完成。
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        //如果没有增强点则不需要代理。
        if (advisors.isEmpty()) {
                return DO_NOT_PROXY;
        }
        return advisors.toArray();
}

...
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        // 1. 寻找所有的增强
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        // 2. 寻找所有增强中适用于bean 的增强并应用
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
                eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
}
复制代码

可以看到两个核心方法 findCandidateAdvisorsfindAdvisorsThatCanApply 。下面我们一个一个来分析。

3.1 寻找所有Advisors - findCandidateAdvisors

前文讲过,Spring aop 注入的自动代理创建器是 AnnotationAwareAspectJAutoProxyCreator,所以AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 的代码如下:

@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 1. 这里是从BeanFactory 中找出来 所有 Advisor 类型的bean。即找到所有配置的Advisor。
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    if (this.aspectJAdvisorsBuilder != null) {
            // 2. buildAspectJAdvisors() 从代码中动态找到了需要的增强点
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}
复制代码

这里可以看到,AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 中通过 super.findCandidateAdvisors(); 调用了父类的 AbstractAdvisorAutoProxyCreator#findCandidateAdvisors 的方法来获取 Advisor。 调用 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 方法来获取Advisor 这两个方法都是为了获取 Advisor,区别在于:

  • super.findCandidateAdvisors(); : 一般获取的都是通过直接注册的 Advisors。比如事务的顾问,直接通过 @Bean 注入到Spring容器中。

  • this.aspectJAdvisorsBuilder.buildAspectJAdvisors() : 主要获取我们通过注解方式动态注册的 Advisors。比如 在 Aop 中根据不同的表达式,每个@Pointcut 注解的切点不同,也就会对不同的Bean起作用,并且对于每个@Pointcut来说都有@Before、@After 等不同的操作,那么每个@Pointcut 以及其对应的操作都会被封装成一个一个的Advisor 返回。下面会有详细解读。

3.1.1 super.findCandidateAdvisors();

super.findCandidateAdvisors(); 说白了就是直接获取 容器中的 Advisor 类型的Bean。 这里调用的实际上是AbstractAdvisorAutoProxyCreator 中的findCandidateAdvisors 方法。这一步最终会调用如下的findAdvisorBeans 方法。其作用根据注释也能明白。获取所有合格的 Advisor Bean(合格并不代表适用当前bean),忽略了FactoryBean 和创建中的bean。

 // org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        // 从缓存中获取 advisorNames。因为每个Bean创建的时候都会进行一次获取,所以对增强的缓存是必须的
        String[] advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
                // Do not initialize FactoryBeans here: We need to leave all regular beans
                // uninitialized to let the auto-proxy creator apply to them!
                // 注释: 不要在这里初始化FactoryBeans:我们需要保留所有未初始化的常规bean,以使自动代理创建者对其应用!  个人理解是防止有的FactoryBean可能会被增强代理,而在这里初始化,则会没有办法进行代理
                // 从 Spring 中获取 Advisor 类型的 beanname 。这里获取到的一般都是硬编码注入的 Advisors 
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                                this.beanFactory, Advisor.class, true, false);
                this.cachedAdvisorBeanNames = advisorNames;
        }
        // 如果没有获取到 Advisors  ,直接返回
        if (advisorNames.length == 0) {
                return new ArrayList<>();
        }
        // 到这一步必定有Advisors ,我们需要通过name来获取到bean的实例 
        List<Advisor> advisors = new ArrayList<>();
        for (String name : advisorNames) {
                // 当前Bean 是否合格,这里调用的是 AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean 直接返回true,供子类扩展。
                if (isEligibleBean(name)) {
                        // 如果 name 指向的 bean 正在创建中则跳过
                        if (this.beanFactory.isCurrentlyInCreation(name)) {
                                if (logger.isTraceEnabled()) {
                                        logger.trace("Skipping currently created advisor '" + name + "'");
                                }
                        }
                        else {
                                try {
                                        // 否则从容器中根据name 和 类型获取到 Advisor 实例,添加到 advisors 集合中
                                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                                }
                                catch (BeanCreationException ex) {
                                        Throwable rootCause = ex.getMostSpecificCause();
                                        // 如果是异常时因为bean正在创建引起的在,则 continue
                                        if (rootCause instanceof BeanCurrentlyInCreationException) {
                                                BeanCreationException bce = (BeanCreationException) rootCause;
                                                String bceBeanName = bce.getBeanName();
                                                if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                                                        if (logger.isTraceEnabled()) {
                                                                logger.trace("Skipping advisor '" + name +
                                                                                "' with dependency on currently created bean: " + ex.getMessage());
                                                        }
                                                        // Ignore: indicates a reference back to the bean we're trying to advise.
                                                        // We want to find advisors other than the currently created bean itself.
                                                        continue;
                                                }
                                        }
                                        throw ex;
                                }
                        }
                }
        }
        // 返回得到的合格的 Advisor 集合
        return advisors;
}
复制代码

3.1.2 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()

this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 的作用就是 在当前的bean工厂中查找带有AspectJ注解的 Aspect bean,并封装成代表他们的Spring Aop Advisor,注入到Spring 中。

基本的思路如下:

  • 获取所有beanName,这一步所有在beanFactory中注册的bean都会被提取出来
  • 遍历所有的beanName, 找出声明AspectJ注解的类,进行进一步处理
  • 对标记为AspectJ注解的类进行Advisors 提取
  • 将提取的结果保存到缓存中。
public List<Advisor> buildAspectJAdvisors() {
        // aspectBeanNames 中缓存了被 @Aspect 修饰的 bean的name
        List<String> aspectNames = this.aspectBeanNames;
        // 如果为空表示尚未缓存,进行缓存解析。这里用了DLC 方式来进行判断
        if (aspectNames == null) {
                synchronized (this) {
                        aspectNames = this.aspectBeanNames;
                        if (aspectNames == null) {
                                List<Advisor> advisors = new ArrayList<>();
                                aspectNames = new ArrayList<>();
                                // 1. 获取所有的beanName。从容器中获取所有的BeanName
                                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                                                this.beanFactory, Object.class, true, false);
                                // 遍历beanname, 找出对应的增强方法
                                for (String beanName : beanNames) {
                                        // 不合法的bean略过,由子类定义规则,默认true
                                        if (!isEligibleBean(beanName)) {
                                                continue;
                                        }
                                        // 注释 :我们必须小心,不要急于实例化bean,因为在这种情况下,它们将由Spring容器缓存,但不会被编织。
                                        // We must be careful not to instantiate beans eagerly as in this case they
                                        // would be cached by the Spring container but would not have been weaved.
                                        // 获取对应 bean 的类型
                                        Class<?> beanType = this.beanFactory.getType(beanName);
                                        if (beanType == null) {
                                                continue;
                                        }
                                        // 2. 如果bean 被 @AspectJ 注解修饰 且不是Ajc 编译, 则进一步处理
                                        if (this.advisorFactory.isAspect(beanType)) {
                                                // 添加到缓存中
                                                aspectNames.add(beanName);
                                                // 封装成AspectMetadata 
                                                AspectMetadata amd = new AspectMetadata(beanType, beanName);
                                                // aspect 存在 SINGLETON、PERTHIS、PERTARGET、PERCFLOW、PERCFLOWBELOW、PERTYPEWITHIN模式。默认为SINGLETON 。暂不明白意义
                                                if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                                        MetadataAwareAspectInstanceFactory factory =
                                                                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                                        // 3. 解析标记AspectJ注解中的增强方法,也就是被 @Before、@Around 等注解修饰的方法,并将其封装成 Advisor
                                                        List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                                        if (this.beanFactory.isSingleton(beanName)) {
                                                                this.advisorsCache.put(beanName, classAdvisors);
                                                        }
                                                        else {
                                                                this.aspectFactoryCache.put(beanName, factory);
                                                        }
                                                        // 保存 Advisor 
                                                        advisors.addAll(classAdvisors);
                                                }
                                                else {
                                                        // Per target or per this.
                                                        // 如果当前Bean是单例,但是 Aspect 不是单例则抛出异常
                                                        if (this.beanFactory.isSingleton(beanName)) {
                                                                throw new IllegalArgumentException("Bean with name '" + beanName +
                                                                                "' is a singleton, but aspect instantiation model is not singleton");
                                                        }
                                                        MetadataAwareAspectInstanceFactory factory =
                                                                        new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                                                        this.aspectFactoryCache.put(beanName, factory);
                                                        advisors.addAll(this.advisorFactory.getAdvisors(factory));
                                                }
                                        }
                                }
                                this.aspectBeanNames = aspectNames;
                                return advisors;
                        }
                }
        }

        if (aspectNames.isEmpty()) {
                return Collections.emptyList();
        }
        // 4. 将所有的增强方法保存到缓存中。
        List<Advisor> advisors = new ArrayList<>();
        for (String aspectName : aspectNames) {
                List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
                if (cachedAdvisors != null) {
                        advisors.addAll(cachedAdvisors);
                }
                else {
                        MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
                        advisors.addAll(this.advisorFactory.getAdvisors(factory));
                }
        }
        return advisors;
}
复制代码

上面的方法一句话总结 : 获取容器中所有被 @Aspect 修饰 && 不是 Ajc 编译 的类,动态解析内容,封装成 Advisor保存到对应集合中。

下面我们来详细看看具体实现:

3.1.2.1 this.advisorFactory.getAdvisors(factory);

在上述代码中,最为复杂的就是增强器(Advisors)获取,也就是 this.advisorFactory.getAdvisors(factory); 这一步, 具体的实现是在 ReflectiveAspectJAdvisorFactory#getAdvisors中。下面我们具体来看代码:

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
        // 获取标记为 AspectJ 的类
        Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        // 获取标记为 AspectJ 的名字
        String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
        // 进行合法性验证
        validate(aspectClass);

        // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
        // so that it will only instantiate once.
        // 这里需要 MetadataAwareAspectInstanceFactory  ,所以这里初始化了一次
        MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                        new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

        List<Advisor> advisors = new ArrayList<>();
        // getAdvisorMethods(aspectClass) 获取 aspectClass 中没有被 @PointCut 注解修饰的方法
        for (Method method : getAdvisorMethods(aspectClass)) {
                // 将方法封装成 Advisor 。如果找不到@PointCut 的信息,则会返回 null。下面详解
                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.
        // 获取 DeclaredParents 注解并处理。@DeclaredParents  注解可以实现指定某些代理类是某些接口的实现。
        for (Field field : aspectClass.getDeclaredFields()) {
                Advisor advisor = getDeclareParentsAdvisor(field);
                if (advisor != null) {
                        advisors.add(advisor);
                }
        }

        return advisors;
}
复制代码

这里根据 切点信息来动态生成了增强器,也就是 Advisor。是根据AOP 的注解解析来的动态生成的。 可以看到,封装的关键的操作还是在 getAdvisor 方法 中,下面我们来详细分析:

// 筛选出合适的方法,并封装成 Advisor 。这里返回的都是 InstantiationModelAwarePointcutAdvisorImpl
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
                int declarationOrderInAspect, String aspectName) {
        // 又进行一次合法性校验
        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
        // 1. 切点信息的获取。这里如果没有被Aspect 系列注解(Pointcut、Around、Before等)修饰会返回null
        AspectJExpressionPointcut expressionPointcut = getPointcut(
                        candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        // 如果获取不到相关信息直接返回null
        if (expressionPointcut == null) {
                return null;
        }
        // 2. 根据切点信息封装成增强器
        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                        this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
复制代码

可以看到在 getAdvisor 方法中的关键两步: 切点信息的获取根据切点信息封装成增强器。下面我们来继续分析

1. 切点信息的获取 - getPointcut

getPointcut 方法的实现很简单,就是判断方法上是否有 AspectJ系列的注解,有则封装。

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        // 获取方法上的注解,包括 Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
        AspectJAnnotation<?> aspectJAnnotation =
                        AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
                return null;
        }
        // 到这里必然有 AspectJ系列的注解了
        // 使用 AspectJExpressionPointcut 实例封装获取的信息
        AspectJExpressionPointcut ajexp =
                        new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
        // 提取出的得到的注解中的表达式
        // 如  @Pointcut("execution(* com.kingfish.aopdemo.controller.AopController.hello(String))") 中的 execution(* com.kingfish.aopdemo.controller.AopController.hello(String))
        // 对于 @Before("pointCut()") 获取的则是 pointCut()
        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        if (this.beanFactory != null) {
                ajexp.setBeanFactory(this.beanFactory);
        }
        return ajexp;
}
复制代码

其中 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); 方法如下:

private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
                Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

// 获取指定方法上的注解并使用  AspectJAnnotation 封装
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
        for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
                AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
                if (foundAnnotation != null) {
                        return foundAnnotation;
                }
        }
        return null;
}
复制代码
2. 根据切点信息封装成增强器 - InstantiationModelAwarePointcutAdvisorImpl

在上面的代码中我们看到,ReflectiveAspectJAdvisorFactory#getAdvisor 最终封装成了一个InstantiationModelAwarePointcutAdvisorImpl 返回。实际上,在 Aop 中所有的增强都由 Advisor 的实现类InstantiationModelAwarePointcutAdvisorImpl 统一封装。我们来看看InstantiationModelAwarePointcutAdvisorImpl 中做了什么事:

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
                Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
                MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
        // 信息的基础赋值
        this.declaredPointcut = declaredPointcut;
        this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
        this.methodName = aspectJAdviceMethod.getName();
        this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
        this.aspectJAdviceMethod = aspectJAdviceMethod;
        this.aspectJAdvisorFactory = aspectJAdvisorFactory;
        this.aspectInstanceFactory = aspectInstanceFactory;
        this.declarationOrder = declarationOrder;
        this.aspectName = aspectName;
        // 懒加载实例
        if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
                // Static part of the pointcut is a lazy type.
                Pointcut preInstantiationPointcut = Pointcuts.union(
                                aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

                // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
                // If it's not a dynamic pointcut, it may be optimized out
                // by the Spring AOP infrastructure after the first evaluation.
                this.pointcut = new PerTargetInstantiationModelPointcut(
                                this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
                this.lazy = true;
        }
        else {
                // A singleton aspect.
                // 我们一般走到这里
                this.pointcut = this.declaredPointcut;
                this.lazy = false;
                this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        }
}

...

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);
}
复制代码

可以看到,InstantiationModelAwarePointcutAdvisorImpl 在封装过程中只是简单的将信息封装在类的实例中,所有的信息只是单纯的赋值。但是需要注意的是,在信息赋值结束后调用了 instantiateAdvice(this.declaredPointcut); 方法,这个方法完成了对于增强器的处理。

因为不同的增强体现的逻辑是不同的,简单来说就是不同的切点信息的动作是不同的,比如 @Before@After 注解的动作就不同, @Before 需要在切点方法前调用, @After 需要在切点方法后调用。这里根据不同的注解封装成了不同的 Advice,用以区分在适当的时候调用适当的方法。

而根据注解中的信息初始化对应的增强器就是在instantiateAdvice 中实现。而instantiateAdvice 中主要还是调用了 this.aspectJAdvisorFactory.getAdvice,因此我们来看 this.aspectJAdvisorFactory.getAdvice 的代码:

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

        Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        validate(candidateAspectClass);

        AspectJAnnotation<?> aspectJAnnotation =
                        AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
                return null;
        }

        // If we get here, we know we have an AspectJ method.
        // Check that it's an AspectJ-annotated class
        if (!isAspect(candidateAspectClass)) {
                throw new AopConfigException("Advice must be declared inside an aspect type: " +
                                "Offending method '" + candidateAdviceMethod + "' in class [" +
                                candidateAspectClass.getName() + "]");
        }

        if (logger.isDebugEnabled()) {
                logger.debug("Found AspectJ method: " + candidateAdviceMethod);
        }

        AbstractAspectJAdvice springAdvice;
        // 根据不同的注解生成不同的通知(增强)
        switch (aspectJAnnotation.getAnnotationType()) {
                case AtPointcut:
                        if (logger.isDebugEnabled()) {
                                logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                        }
                        return null;
                case AtAround:
                        springAdvice = new AspectJAroundAdvice(
                                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                        break;
                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;
                default:
                        throw new UnsupportedOperationException(
                                        "Unsupported advice type on method: " + candidateAdviceMethod);
        }

        // Now to configure the advice...
        springAdvice.setAspectName(aspectName);
        springAdvice.setDeclarationOrder(declarationOrder);
        String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
        if (argNames != null) {
                springAdvice.setArgumentNamesFromStringArray(argNames);
        }
        springAdvice.calculateArgumentBindings();

        return springAdvice;
}
复制代码

可以看到,Spring会根据不同的注解生成不同的增强器(通知)。比如 AspectJAroundAdviceAspectJMethodBeforeAdvice 等,从而完成不同的注解所需的动作。

这里举个简单例子总结一下: 如下:

@Component
@Aspect
public class AopDemo {
    
    @Pointcut("execution(* com.kingfish.aopdemo.controller.AopController.hello(String)) && args(msg)")
    public void pointCut(String msg) {
        System.out.println("AopDemo.pointCut : msg = " + msg);
    }

    @After("pointCut(msg)")
    public void after(String msg) {
        System.out.println("after msg = " + msg);
    }


    @Before("pointCut(msg)")
    public void before(String msg) {
        System.out.println("before msg = " + msg);
    }
}
复制代码

如上一个类,

  • 容器启动后会加载硬编码注入的Advisor,加载结束后扫描 @Aspect 注解类。
  • 解析注解类里面的非 @PointCut 方法。即after、before 方法,对其注解进行信息进行解析,封装成 InstantiationModelAwarePointcutAdvisorImpl
  • InstantiationModelAwarePointcutAdvisorImpl 中存在的 PointCut 和 Advice 两大属性,PointCut 代表切入点,Advice 代表增强的具体操作,根据不同的注解类型,加载不同的Advice 实现类。如下

imagen.png 最终会封装成两个 InstantiationModelAwarePointcutAdvisorImplAfter 方法对应 是 AspectJAfterAdviceBefore 方法对应的是 AspectJMethodBeforeAdvicePointcut 都是 pointCut(msg)

3.2 筛选合适的Advisors - findAdvisorsThatCanApply

经历了第一步,也仅仅是将所有的顾问(Advisors),也就是增强器,全部查找出来。但是并非所有的Advisors 都适用于当前bean。所以这一步的目的是为了过滤出适合当前bean的增强器。

protected List<Advisor> findAdvisorsThatCanApply(
                List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
            return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
            ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}
复制代码

可以看到关键内容还是在 AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); 所以我们继续往下看。代码如下:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 首先处理引介增强
    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;
            }
            // 对于普通bean 的处理
            if (canApply(candidate, clazz, hasIntroductions)) {
                    eligibleAdvisors.add(candidate);
            }
    }
    return eligibleAdvisors;
}
复制代码

引介增强和普通的增强处理是不同的,所以需要分开处理。而通过上面的代码,我们可以看到关键逻辑在 canApply函数中,因此我们直接看这个函数。

public static boolean canApply(Advisor advisor, Class<?> targetClass) {
        return canApply(advisor, targetClass, false);
}
....
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
        // 基础篇曾介绍过,IntroductionAdvisor 和 PointcutAdvisor 的区别在于 PointcutAdvisor 的切入点更细。我们这里的Advisor都是PointcutAdvisor 类型
        if (advisor instanceof IntroductionAdvisor) {
                return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
        }
        else if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pca = (PointcutAdvisor) advisor;
                return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {
                // It doesn't have a pointcut so we assume it applies.
                return true;
        }
}
....

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {
                return false;
        }
        // 获取切点的方法匹配器
        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {
                // No need to iterate the methods if we're matching any method anyway...
                return true;
        }
        // 这里 introductionAwareMethodMatcher  的实现是 AspectJExpressionPointcut
        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
                introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<>();
        if (!Proxy.isProxyClass(targetClass)) {
                classes.add(ClassUtils.getUserClass(targetClass));
        }
        classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

        for (Class<?> clazz : classes) {
                // 获取当前bean的所有方法
                Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
                for (Method method : methods) {
                        // 在这里判断方法是否匹配
                        if (introductionAwareMethodMatcher != null ?
                                        // 这里调用 AspectJExpressionPointcut#matches
                                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                                        methodMatcher.matches(method, targetClass)) {
                                return true;
                        }
                }
        }

        return false;
}
复制代码

注:introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) 实际上调用的是 AspectJExpressionPointcut#matches,该方法中会通过 AspectJExpressionPointcut#getTargetShadowMatch 调用 AspectJExpressionPointcut#getShadowMatch ,在该方法中对表达式进行了校验,并返回了一个 ShadowMatch 类,包含了校验后的结果信息。

从上面我们可以看到 Pointcut 匹配的需要满足下面两个条件:

  • pc.getClassFilter().matches(targetClass) 返回true
  • pc.getMethodMatcher().matches(method, targetClass) 返回true

3.3 extendAdvisors(eligibleAdvisors)

AspectJAwareAdvisorAutoProxyCreator#extendAdvisors代码如下:

@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
   // 创建增强器链
   AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
// 创建增强器链
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
   // Don't add advisors to an empty list; may indicate that proxying is just not required
   if (!advisors.isEmpty()) {
      boolean foundAspectJAdvice = false;
      for (Advisor advisor : advisors) {
         // Be careful not to get the Advice without a guard, as this might eagerly
         // instantiate a non-singleton AspectJ aspect...
         if (isAspectJAdvice(advisor)) {
            foundAspectJAdvice = true;
            break;
         }
      }
      // 增强器链中 有ExposeInvocationInterceptor(拦截器)
      if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
         advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
         return true;
      }
   }
   return false;
}
复制代码

在advices中第0个位置 增加ExposeInvocationInterceptor.ADVISOR,创建增强器链。

3.4 总结

getAdvicesAndAdvisorsForBean 方法的作用就是筛选出适用于当前bean的Advisor。简单来说就是两步:

  • AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 挑选出所有的 Advisor。在 其中 通过 super.findCandidateAdvisors() 调用了 AbstractAdvisorAutoProxyCreator#findCandidateAdvisors 来完成了对硬编码注入的Advisor 的获取解析返回。随后通过 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 方式解析了 Aop 注解方式动态封装的Advisor并保存。
  • findAdvisorsThatCanApply 通过 Advisor 中的Pointcut 筛选出适合当前bean的 Advisor。

4. 创建代理类 - createProxy

上小节已经分析到了 Spring将已经找到所有适用于当前bean 的Advisor 集合。下面就要创建代理对象了,而代理对象的创建是从 AbstractAutoProxyCreator#createProxy 开始。下面我们就来看看代理对象的创建过程。

4.1 ProxyFactory

ProxyFactory 的结构图如下: imagen.png

在代理对象的创建过程中,实际上是委托给 ProxyFactory 来完成的。ProxyFactory 在创建过程中保存了筛选后的 Advisor 集合以及其他的一些属性。而在后面创建代理类的时候,将 ProxyFactory 作为参数传递给了 JdkDynamicAopProxyObjenesisCglibAopProxy。这个在后面的代码分析中会有详细说明。

4.2 创建代理类 - AbstractAutoProxyCreator#createProxy

AbstractAutoProxyCreator#createProxy 的代码如下:

// 这里的入参 beanClass :当前BeanClass, 
// beanName : 当前BeanName
// specificInterceptors : 中篇中寻找出来的 Advisor
// targetSource : SingletonTargetSource 目标类是单例 拥有给定对象的TargetSource接口的实现。 这是Spring AOP框架使用的TargetSource接口的默认实现。 通常不需要在应用程序代码中创建此类的对象。
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);
        // 判断当前bean 是使用 TargetClass 代理还是接口代理
        if (!proxyFactory.isProxyTargetClass()) {
                // 检查 proxyTargeClass设置以及preservetargetClass 属性
                if (shouldProxyTargetClass(beanClass, beanName)) {
                        proxyFactory.setProxyTargetClass(true);
                }
                else {
                        evaluateProxyInterfaces(beanClass, proxyFactory);
                }
        }
        // 将拦截器 Interceptors 封装成增强器 Advisor
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        // 加入增强器
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        // 定制代理
        customizeProxyFactory(proxyFactory);
        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
                proxyFactory.setPreFiltered(true);
        }
        // 在这里面就封装出了ProxyFactory,并交由其来完成剩下的代理工作。
        return proxyFactory.getProxy(getProxyClassLoader());
}
复制代码

代码中已经有详细的注释了,可以看到代理类的创建Spring委托给 ProxyFactory 去处理,而在此函数中主要是对 ProxyFactory 的初始化操作:

  • 获取当前类的属性
  • 添加代理接口
  • 封装Advisor 并加入到ProxyFactory 中
  • 设置要代理的类
  • 通过customizeProxyFactory定制代理类 ,对ProxyFactory 进一步封装
  • 进行获取代理操作 下面我们主要下面两个方法:

4.2.1 buildAdvisors(beanName, specificInterceptors);

这一步的目的是将 Interceptors 封装成增强器 Advisor。虽然我们之前动态解析的都是 Advisor ,但是保不齐用户自己注入的并不是Advisor 类型,所以这里需要一个转换。

需要注意的是:这里的参数 就是 Object[] specificInterceptors 就是 getAdvicesAndAdvisorsForBean 方法返回的 Advisor,通过对 getAdvicesAndAdvisorsForBean 方法的分析我们可以得知, specificInterceptors 应该全是 InstantiationModelAwarePointcutAdvisorImpl 类型。

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
        // Handle prototypes correctly...
        // 解析注册的所有 Interceptor Name。即我们可以手动添加一些 拦截器,这里将手动添加的拦截器保存到commonInterceptors  中
        Advisor[] commonInterceptors = resolveInterceptorNames();

        List<Object> allInterceptors = new ArrayList<>();
        if (specificInterceptors != null) {
                // 加入拦截器
                allInterceptors.addAll(Arrays.asList(specificInterceptors));
                if (commonInterceptors.length > 0) {
                        if (this.applyCommonInterceptorsFirst) {
                                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                        }
                        else {
                                allInterceptors.addAll(Arrays.asList(commonInterceptors));
                        }
                }
        }
        // ... 日志打印

        Advisor[] advisors = new Advisor[allInterceptors.size()];
        for (int i = 0; i < allInterceptors.size(); i++) {
                // 拦截器进行转化为 Advisor
                advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
        }
        return advisors;
}

...
//  this.interceptorNames 是自己通过set设置的属性。在基础篇中Advice 有过类似的设置。我们这里是没有的
private Advisor[] resolveInterceptorNames() {
        BeanFactory bf = this.beanFactory;
        ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
        List<Advisor> advisors = new ArrayList<>();
        // 将 interceptorNames 获取到的拦截器保存起来,并返回。
        for (String beanName : this.interceptorNames) {
                if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
                        Assert.state(bf != null, "BeanFactory required for resolving interceptor names");
                        Object next = bf.getBean(beanName);
                        advisors.add(this.advisorAdapterRegistry.wrap(next));
                }
        }
        return advisors.toArray(new Advisor[0]);
}
复制代码

我们下面来看一下 this.advisorAdapterRegistry.wrap(allInterceptors.get(i)); 的实现。

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        // 如果 adviceObject  本身就是 Advisor则不需进一步操作
        if (adviceObject instanceof Advisor) {
                return (Advisor) adviceObject;
        }
        // 此封装方法只能处理Advisor 和 Advice两种类型,如果不是将不能封装
        if (!(adviceObject instanceof Advice)) {
                throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
                // So well-known it doesn't even need an adapter.
                // 如果是MethodInterceptor 类型则使用 DefaultPointcutAdvisor 封装
                return new DefaultPointcutAdvisor(advice);
        }
        // 如果存在 Advisor 的适配器则同样需要进行封装。
        for (AdvisorAdapter adapter : this.adapters) {
                // Check that it is supported.
                if (adapter.supportsAdvice(advice)) {
                        return new DefaultPointcutAdvisor(advice);
                }
        }
        throw new UnknownAdviceTypeException(advice);
}
复制代码

DefaultAdvisorAdapterRegistry#wrap 方法也很简单,就是将 adviceObject 包装成 Advisor

4.2.2 proxyFactory.getProxy(getProxyClassLoader());

上述代码中 proxyFactory.getProxy(getProxyClassLoader()); 会继续调用到 DefaultAopProxyFactory#createAopProxy。如下:

public Object getProxy(@Nullable ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
}
复制代码

显然意见我们需要将这个内容分为两步: createAopProxy()getProxy(classLoader)

4.2.2.1 ProxyCreatorSupport#createAopProxy

我们可以看到,ProxyCreatorSupport#createAopProxy 会调用 DefaultAopProxyFactory#createAopProxy,并且将this作为参数传递了过去。而此时的 this,正是上面提到的创建的 ProxyFactory

protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
                activate();
        }
        // 这里我们需要注意的是 ,这里 createAopProxy 传入的是 this。也就是说这里参数传递实际上是ProxyFactroy
        return getAopProxyFactory().createAopProxy(this);
}
复制代码

这里我们再来看 DefaultAopProxyFactory#createAopProxy 的实现

@Override
// 这里的参数 AdvisedSupport config 即是之前创建的ProxyFactory。这里又将其传递给了AopProxy 
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);
                }
                return new ObjenesisCglibAopProxy(config);
        }
        else {
                return new JdkDynamicAopProxy(config);
        }
}
复制代码

在这个方法中我们可以看到 Aop代理使用了 JDK动态代理和 Cglib动态代理两种动态代理模式,并根据某些参数来进行选择代理方式.

createAopProxy 代码中我们可以看到几个参数:

  • optimize: se usa para controlar si el proxy creado por CGlib usa una estrategia de optimización agresiva, generalmente falso predeterminado, no válido para el proxy dinámico JDK.

  • proxyTargetClass: si es verdadero, la clase de destino en sí misma es un proxy, en lugar de un proxy de la interfaz de la clase de destino, creando un proxy cglib.

  • hasNoUserSuppliedProxyInterfaces: Si hay una interfaz de proxy que es:

  • Si el objeto de destino implementa la interfaz, el proxy dinámico JDK se utilizará para implementar AOP de forma predeterminada.

  • Si el objeto de destino implementa la interfaz, puede forzar el uso del proxy dinámico CGLIB para implementar AOP

  • Si el objeto de destino no implementa la interfaz, se debe usar el proxy CGLIB y Spring cambiará automáticamente entre el proxy dinámico JDK y el proxy CGLIB.

Artículo de referencia

Anotación de código fuente de Spring5 Dirección
de github Análisis en profundidad del código fuente de Spring (2.ª edición)
Análisis de código fuente de Spring
Notas de análisis en profundidad del código fuente de Spring
Análisis de código fuente y anotación
de Spring Tutorial de estación B de desarrollo basado en anotaciones de Spring

Supongo que te gusta

Origin juejin.im/post/7136748117931589662
Recomendado
Clasificación