Spring AOP源码:代理的创建过程

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring AOP源码:代理的创建过程

文章导航

Spring AOP:基本概述

Spring AOP源码:配置文件解析过程

Spring AOP源码:配置文件解析过程

Spring AOP源码:拦截器责任链处理过程

目录

文章导航

前言

正文

方法1:postProcessAfterInitialization

方法2:wrapIfNecessary

方法3:shouldSkip

方法4:getAdvicesAndAdvisorsForBean

方法5:findAdvisorsThatCanApply

方法6:extendAdvisors

方法7:createProxy

方法8:getProxy

方法9:createAopProxy

总结

前言

上篇文章讲解了AOP解析工作,将配置文件解析并封装成beanDefinition,由于配置文件中有5个通知方法,before、after、around、after-returning、after-throwing,这里会将其解析成5个advisor通知类。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="accountAdvice" class="service.impl.AccountAdvice" ></bean>
    <bean id="myAccount" class="service.impl.MyAccount" ></bean>
    <aop:config>
      <aop:pointcut id="pointCut" expression="execution(* service.impl.*.*())"/>
      <aop:aspect ref="accountAdvice">
        <aop:after method="after" pointcut-ref="pointCut"></aop:after>
        <aop:before method="before" pointcut-ref="pointCut"></aop:before>
        <aop:around method="around" pointcut-ref="pointCut"></aop:around>
        <aop:after-returning method="afterReturn" pointcut-ref="pointCut"></aop:after-returning>
        <aop:after-throwing method="afterThrow" pointcut-ref="pointCut"></aop:after-throwing>
      </aop:aspect>
    </aop:config>
</beans>

解析后的BeanDefinitions集合信息:

正文

之前Spring IOC文章讲解过Bean的实例化过程,在实例化Bean之后会进行属性填充(populateBean)、执行初始化方法(initializeBean)。而代理类的生成就在执行初始化方法(initializeBean)中,在该方法中会执行beanPostProcessor方法,如果该bean需要代理,则会进行代理工作。


本章案例中需要被代理的类是myAccount,所以我们来到myAccount实例化过程中的initializeBean方法中;

  protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // 如果安全管理器不为空
    if (System.getSecurityManager() != null) {
      // 以特权的方式执行回调bean中的Aware接口方法
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
        invokeAwareMethods(beanName, bean);
        return null;
      }, getAccessControlContext());
    }
    else {
      // Aware接口处理器,调用BeanNameAware、BeanClassLoaderAware、beanFactoryAware
      invokeAwareMethods(beanName, bean);
    }
    Object wrappedBean = bean;
    //如果mdb不为null || mbd不是"synthetic"。一般是指只有AOP相关的prointCut配置或者Advice配置才会将 synthetic设置为true
    if (mbd == null || !mbd.isSynthetic()) {
      // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessBeforeInitialization初始化方法。
      // 返回的Bean实例可能是原始Bean包装器
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    try {
      //调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法
      invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
      //捕捉调用初始化方法时抛出的异常,重新抛出Bean创建异常:调用初始化方法失败
      throw new BeanCreationException(
          (mbd != null ? mbd.getResourceDescription() : null),
          beanName, "Invocation of init method failed", ex);
    }
    //如果mbd为null || mbd不是"synthetic"
    if (mbd == null || !mbd.isSynthetic()) {
      // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。
      // 返回的Bean实例可能是原始Bean包装器
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    //返回包装后的Bean
    return wrappedBean;
  }

AOP的代理类生成过程在BeanPostProcessor的after方法中调用

applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName),见方法1详解

方法1:postProcessAfterInitialization

进入到AspectJAwareAdivsorAutoProxyCreator类中的postProcessAfterInitialization方法;

  public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
      // 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型则beanName名称前面会加上“&”符号
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      // 判断当前bean是否正在被代理,如果正在被代理则不进行代理操作
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
        // 如果它需要被代理,则需要封装指定的bean
        return wrapIfNecessary(bean, beanName, cacheKey);
      }
    }
    return bean;
  }

wrapIfNecessary(bean, beanName, cacheKey),见方法2详解

方法2:wrapIfNecessary

  protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 判断是否已经处理过,处理过则直接返回
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
    }
    // 这里advisedBeans缓存了已经进行了代理流程处理的bean,如果缓存中存在,则可以直接返回
    //这里存在两种bean,一种是不需要代理的bean,一种是真正需要代理的,避免下次判断时可以直接返回,不走下面处理逻辑
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
    }
    // 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,如:Advice、Pointcut、Advisor、AopInfrastructureBean的实现类
    // 不用进行代理的;shouldSkip()则用于判断当前bean是否应该被略过
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      // 对当前bean进行缓存
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
    }
    // Create proxy if we have advice.
    // 尝试获取能够匹配当前被代理类的通知类信息
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 如果找到合适的通知类,则进行代理操作
    if (specificInterceptors != DO_NOT_PROXY) {
      // 对当前bean的代理状态进行缓存
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      // 根据获取到的Advices和Advisors为当前bean生成代理对象
      Object proxy = createProxy(
          bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      // 缓存生成的代理bean的类型,并且返回生成的代理bean
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
    }
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
  }

shouldSkip(bean.getClass(), beanName),见方法3详解

getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null),见方法4详解

createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)),见方法7详解

方法3:shouldSkip

  protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    //尝试从beanFacotry工厂中获取配置文件中定义好的五个通知方法,它们被封装成了advisor对象,所以这里能获取到5个
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
      //判断通知类中的切面类名称,如果当前bean是切面类,则不应该被代理,会跳过
      if (advisor instanceof AspectJPointcutAdvisor &&
          ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
        return true;
      }
    }
    return super.shouldSkip(beanClass, beanName);
  }

方法4:getAdvicesAndAdvisorsForBean

  protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    // 找合适的增强器对象
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    // 若为空表示没找到
    if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
    }
    return advisors.toArray();
  }
  protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 将当前系统中所有的切面类的切面逻辑进行封装,从而得到目标Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 对获取到的所有Advisor进行判断,判断其中的表达式是否能够匹配上要被代理的类
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 提供的hook方法,用于对目标Advisor进行扩展
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
      // 对需要代理的Advisor按照一定的规则进行排序
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
  }

findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName),见方法5详解

extendAdvisors(eligibleAdvisors),见方法6详解

方法5:findAdvisorsThatCanApply

  protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
      // 从候选的通知器中找到合适正在创建的实例对象的通知器
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
      ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
  }
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    // 若候选的增强器集合为空 直接返回
    if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
    }
    // 定义一个合适的增强器集合对象
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 循环我们候选的通知类对象
    for (Advisor candidate : candidateAdvisors) {
      // 判断我们的通知类对象是不是实现了IntroductionAdvisor 
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
        eligibleAdvisors.add(candidate);
      }
    }
    // 判断是否有合适的通知类
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    for (Advisor candidate : candidateAdvisors) {
      // 判断我们的通知类对象是不是实现了IntroductionAdvisor
      if (candidate instanceof IntroductionAdvisor) {
        // already processed
        // 在上面已经处理过,不需要处理
        continue;
      }
      // 真正的判断增强器是否合适当前类型,这里会通过切入点表达式进行判断是否适用于当前类
      if (canApply(candidate, clazz, hasIntroductions)) {
        eligibleAdvisors.add(candidate);
      }
    }
    return eligibleAdvisors;
  }

方法6:extendAdvisors

  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;
        }
      }
      //这里会往advisors缓存中添加ExposeInvocationInterceptor对象,该对象为后续代理类调用过程中的拦截链做准备
      if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
        advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
        return true;
      }
    }
    return false;
  }

方法7:createProxy

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // 给bean定义设置暴露属性
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    // 创建代理工厂
    ProxyFactory proxyFactory = new ProxyFactory();
    // 获取当前类中相关属性
    proxyFactory.copyFrom(this);
    // 决定对于给定的bean是否应该使用targetClass而不是他的接口代理,检查proxyTargetClass设置以及preserverTargetClass属性
    if (!proxyFactory.isProxyTargetClass()) {
      // 判断是 使用jdk动态代理 还是cglib代理
      //如果被代理类有preserveTargetClass,则设置ProxyTargetClass为true,尝试使用Cglib进行代理
      if (shouldProxyTargetClass(beanClass, beanName)) {
        proxyFactory.setProxyTargetClass(true);
      }
      else {
        // 判断是否有实现接口,如果没有实现接口则设置setProxyTargetClass为true,尝试使用Cglib进行代理
        evaluateProxyInterfaces(beanClass, proxyFactory);
      }
    }
    // 将被代理类名称及其适配的通知对象构建通知类
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    // 设置到要代理的类
    proxyFactory.setTargetSource(targetSource);
    //空方法,用于子类拓展实现
    customizeProxyFactory(proxyFactory);
    // 控制代理工程被配置之后,是否还允许修改通知,默认值是false
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
    }
    // 真正创建代理对象
    return proxyFactory.getProxy(getProxyClassLoader());
  }

proxyFactory.getProxy(getProxyClassLoader()),见方法8详解

方法8:getProxy

  public Object getProxy(@Nullable ClassLoader classLoader) {
    // createAopProxy() 用来创建我们的代理工厂
    return createAopProxy().getProxy(classLoader);
  }
  protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
      // 监听调用AdvisedSupportListener实现类的activated方法
      activate();
    }
    // 通过AopProxyFactory获得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
    return getAopProxyFactory().createAopProxy(this);
  }

getAopProxyFactory().createAopProxy(this),见方法9详解

方法9:createAopProxy

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 这段代码用来判断选择哪种创建代理对象的方式
    // config.isOptimize()   是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false
    // config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false
    // hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型是SpringProxy类型
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      // 上面的三个方法有一个为true的话,则进入到这里
      // 从AdvisedSupport中获取被代理类
      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.");
      }
      // 判断目标类是否是接口 如果目标类是接口的话,则还是使用JDK的方式生成代理对象
      // 如果目标类是Proxy的子类或其实现类时,使用JDK动态代理
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
        return new JdkDynamicAopProxy(config);
      }
      // 配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象
      return new ObjenesisCglibAopProxy(config);
    }
    else {
      // 使用JDK的提供的代理方式生成代理对象
      return new JdkDynamicAopProxy(config);
    }
  }

JDK动态代理根Cglib动态代理在前面的文章中我们讲解过其源码实现过程,可以看这两篇文章进行学习,过程跟Spring AOP过程差不多。

总结

1.当切面类指定了proxy-target-class="true"属性时,代表要使用Cglib(proxyTargetClass属性会为true),此时有机会是Cglib代理。

2.条件1不满足时,看被代理类是否有preserverTargetClass属性,且值为true时,会将proxyTargetClass属性设置为true,此时有机会是Cglib代理。

3.optimize为true时,此时有机会是Cglib代理。

4.被代理类只有一个接口,并且该接口是SpringProxy类型,此时有机会是Cglib代理。

5.被代理类没有实现接口,此时会将proxyTargetClass属性设置为true,此时有机会是Cglib代理。

以上5个条件满足其中1个,且被代理类不是接口或不是Proxy的子类或者实现类时使用Cglib代理。


因此,我们可以得出结论:


被代理类没有接口时不一定使用Cglib进行代理,因为可能被代理类是一个接口或者是Proxy的子类或者实现类

被代理类有接口时不一定使用JDK进行代理:

有可能切面类指定了proxyTargetClass为true

有可能被代理类的只有一个接口且是SpringProxy类型

有可能代理工厂的optimize属性为true


目录
相关文章
|
6天前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
6天前
|
XML 缓存 Java
手写Spring源码(简化版)
Spring包下的类、手写@ComponentScan注解、@Component注解、@Autowired注解、@Scope注解、手写BeanDefinition、BeanNameAware、InitializingBean、BeanPostProcessor 、手写AnnotationConfigApplicationContext
手写Spring源码(简化版)
|
6天前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
23天前
|
人工智能 前端开发 Java
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
本文介绍了如何使用 **Spring Cloud Alibaba AI** 构建基于 Spring Boot 和 uni-app 的聊天机器人应用。主要内容包括:Spring Cloud Alibaba AI 的概念与功能,使用前的准备工作(如 JDK 17+、Spring Boot 3.0+ 及通义 API-KEY),详细实操步骤(涵盖前后端开发工具、组件选择、功能分析及关键代码示例)。最终展示了如何成功实现具备基本聊天功能的 AI 应用,帮助读者快速搭建智能聊天系统并探索更多高级功能。
168 2
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
|
7天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
20天前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
18 0
Spring高手之路22——AOP切面类的封装与解析
|
19天前
|
Java Spring XML
掌握面向切面编程的秘密武器:Spring AOP 让你的代码优雅转身,横切关注点再也不是难题!
【8月更文挑战第31天】面向切面编程(AOP)通过切面封装横切关注点,如日志记录、事务管理等,使业务逻辑更清晰。Spring AOP提供强大工具,无需在业务代码中硬编码这些功能。本文将深入探讨Spring AOP的概念、工作原理及实际应用,展示如何通过基于注解的配置创建切面,优化代码结构并提高可维护性。通过示例说明如何定义切面类、通知方法及其应用时机,实现方法调用前后的日志记录,展示AOP在分离关注点和添加新功能方面的优势。
30 0
|
28天前
|
缓存 安全 Java
Spring AOP 中两种代理类型的限制
【8月更文挑战第22天】
13 0
|
28天前
|
Java Spring
|
4月前
|
安全 Java Spring
Spring之Aop的底层原理
Spring之Aop的底层原理