9.Spring AOP源码解析

Spring AOP源码解析

AOP核心概念

官网地址:https://docs.spring.io/spring/docs/5.2.8.RELEASE/spring-framework-reference/core.html#aop-introduction-defn

AOP基本概念

image-20241223095923081

Spring包含的五种通知

image-20241223100306000

AOP代理方式

Spring AOP有两种代理方式:JDK 动态代理和CGLIB动态代理;默认使用JDK动态代理

image-20241223100406453

Spring中AOP用法

pom配置

在pom.xml中依赖两个jar包,如下:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>
</dependencies>

目标类

public class BeanQ {

   public void do1(String task, int time) {
      System.out.println("-------------do1 do " + task + " time:" + time);
   }

   public String service1(String name) {
      System.out.println("-------------servce1 do " + name);
      return name;
   }

   public String service2(String name) {
      System.out.println("-------------servce2 do " + name);
      if (!"s1".equals(name)) {
         throw new IllegalArgumentException("参数 name != s1, name=" + name);
      }

      return name + " hello!";
   }
}

Advisor方式

基于Advice接口的类实现

  • 掌握用法:

    编程提供Advice,实现对应的Advice接口

    配置Advisor (advice + pointcut)

  • Xml 配置方式

    注意点:aop:config 的属性了解

  • 掌握spring Aop 的API

    Advice:接口实现

    Pointcut:字符串表达式

Advisor:xml标签配置

image-20241223100939050

application.xml配置如下:

<?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:context="http://www.springframework.org/schema/context"
    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/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
   
   <bean id="BeanQ" class="edu.dongnao.courseware.spring.aop.BeanQ" />
   
   <!--将advice做为bean放入容器-->
   <bean id="myBeforeAdvice" class="edu.dongnao.courseware.spring.aop.MyBeforeAdvice" />
   <bean id="yyArroundAdvice" class="edu.dongnao.courseware.spring.aop.MyArroundAdvice" />
   
   <!--第一种方式:advisor 配置切点和通知,aop下以do开头的方法-->
   <!--
   expose-proxy="false" 是否暴露当前代理对象为ThreadLocal模式
   proxy-target-class="false" 是否使用代理类的形式
   -->
   <aop:config>
      <aop:pointcut id="doMethods" expression="execution(* edu.dongnao.courseware.spring.aop.*.do*(..))" />
      <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
      <aop:advisor advice-ref="yyArroundAdvice"
         pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))"/>
   </aop:config >
   
   <!-- 配置了包含advice方法的Bean -->
   <bean id="aspectAdviceBean" class="edu.dongnao.courseware.spring.aop.AspectAdviceBean" />
   
   <!--第二种方式:aspect-->
   <!--proxy-target-class表示使用CGLIB方式处理代理类-->
   <!--aop下以service开头的方法-->
   <aop:config>
      <aop:pointcut id="services" expression="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))" />
      <aop:aspect id="a1" ref="aspectAdviceBean" order="1">
         <aop:before method="before1" pointcut-ref="doMethods" />
         <aop:before method="before2" pointcut-ref="doMethods"/>
         <!-- 
         and args(tk,..),还需要匹配参数,第一个参数类型必须与Advice中tk一致
         arg-name 
         -->
         <aop:before method="before3" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,..)"/>
         <aop:before method="before4" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,ti)"/>
         <aop:around method="arround1" pointcut-ref="services"/>
         <aop:around method="arround2" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..)) and args(name)"/>
         <aop:after-returning method="afterReturning" pointcut-ref="services" returning="retValue"/>
         <aop:after-throwing method="afterThrowing" pointcut-ref="services" throwing="e"/>
         <aop:after method="after" pointcut-ref="services"/>
      </aop:aspect>
   </aop:config>
   
   
   <bean id="aspectAdviceBeanUseAnnotation" class="edu.dongnao.courseware.spring.aop.AspectAdviceBeanUseAnnotation" />
   
</beans>
通知接口实现
/**
 前置通知
*/
public class MyBeforeAdvice implements MethodBeforeAdvice {

   @Override
   public void before(Method method, Object[] args, Object target) throws Throwable {
      System.out.println("------ MyBeforeAdvice before 增强 " + target + " " + method);
   }

}
/**
 环绕通知
*/
public class MyArroundAdvice implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("--------- 环绕 -前增强");
		Object ret = invocation.proceed();
		System.out.println("--------- 环绕 -后增强");
		return ret;
	}

}

Aspect方式

Aspect的advice是基于方法的。

掌握它的用法:

  1. 定义包含Advice方法的Bean 类

  2. 配置Bean 定义

  3. 配置Aspect (引用包含advice方法的bean),在里面配置各种Advice(method + pointcut)

Aspect的XML方式
Xml 配置方式

image-20241223101344905

<?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:context="http://www.springframework.org/schema/context"
    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/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
   
   <bean id="BeanQ" class="edu.dongnao.courseware.spring.aop.BeanQ" />
   
   <!--将advice做为bean放入容器-->
   <bean id="myBeforeAdvice" class="edu.dongnao.courseware.spring.aop.MyBeforeAdvice" />
   <bean id="yyArroundAdvice" class="edu.dongnao.courseware.spring.aop.MyArroundAdvice" />
   
   <!--第一种方式:advisor 配置切点和通知,aop下以do开头的方法-->
   <!--
   expose-proxy="false" 是否暴露当前代理对象为ThreadLocal模式
   proxy-target-class="false" 是否使用代理类的形式
   -->
   <aop:config>
      <aop:pointcut id="doMethods" expression="execution(* edu.dongnao.courseware.spring.aop.*.do*(..))" />
      <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
      <aop:advisor advice-ref="yyArroundAdvice"
         pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))"/>
   </aop:config >
   
   <!-- 配置了包含advice方法的Bean -->
   <bean id="aspectAdviceBean" class="edu.dongnao.courseware.spring.aop.AspectAdviceBean" />
   
   <!--第二种方式:aspect-->
   <!--proxy-target-class表示使用CGLIB方式处理代理类-->
   <!--aop下以service开头的方法-->
   <aop:config>
      <aop:pointcut id="services" expression="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))" />
      <aop:aspect id="a1" ref="aspectAdviceBean" order="1">
         <aop:before method="before1" pointcut-ref="doMethods" />
         <aop:before method="before2" pointcut-ref="doMethods"/>
         <!-- 
         and args(tk,..),还需要匹配参数,第一个参数类型必须与Advice中tk一致
         arg-name 
         -->
         <aop:before method="before3" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,..)"/>
         <aop:before method="before4" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.do*(..)) and args(tk,ti)"/>
         <aop:around method="arround1" pointcut-ref="services"/>
         <aop:around method="arround2" pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..)) and args(name)"/>
         <aop:after-returning method="afterReturning" pointcut-ref="services" returning="retValue"/>
         <aop:after-throwing method="afterThrowing" pointcut-ref="services" throwing="e"/>
         <aop:after method="after" pointcut-ref="services"/>
      </aop:aspect>
   </aop:config>
   
   
   <bean id="aspectAdviceBeanUseAnnotation" class="edu.dongnao.courseware.spring.aop.AspectAdviceBeanUseAnnotation" />
   
</beans>
通知类
public class AspectAdviceBean {

   public void before1() {
      System.out.println("----------- AspectAdviceBean before1 增强 ");
   }

   public void before2(JoinPoint jp) {
      System.out.println("----------- AspectAdviceBean before2 增强 for " + jp);
   }
   
   /*
    * 也可以不需要joinpoint
    */
   public void before3(String tk) {
      System.out.println("----------- AspectAdviceBean before3  增强  参数tk= " + tk);
   }

   public void before4(String tk, int ti) {
      System.out.println("----------- AspectAdviceBean before4  增强  参数tk= " + tk + " ti=" + ti);
   }

   /*
    * 如果需要joinpoint,就作为第一个参数传入使用。
    */
   public Object arround1(ProceedingJoinPoint pjp) throws Throwable {
      System.out.println("----------- AspectAdviceBean arround1 环绕-前增强 for " + pjp);
      Object ret = pjp.proceed();
      System.out.println("----------- AspectAdviceBean arround1 环绕-后增强 for " + pjp);
      return ret;
   }

   public Object arround2(ProceedingJoinPoint pjp, String name) throws Throwable {
      System.out.println("--------- AspectAdviceBean arround2 参数 name=" + name);
      System.out.println("----------- AspectAdviceBean arround2 环绕-前增强 for " + pjp);
      Object ret = pjp.proceed();
      System.out.println("----------- AspectAdviceBean arround2 环绕-后增强 for " + pjp);
      return ret;
   }

   public void afterReturning(Object retValue) {
      System.out.println("----------- AspectAdviceBean afterReturning 增强 , 返回值为: " + retValue);
   }
   /*
    * 因为需要对异常进行处理,所以需要Exception参数
    */
   public void afterThrowing(JoinPoint jp, Exception e) {
      System.out.println("----------- AspectAdviceBean afterThrowing 增强  for " + jp);
      System.out.println("----------- AspectAdviceBean afterThrowing 增强  异常 :" + e);
   }

   public void after(JoinPoint jp) {
      System.out.println("----------- AspectAdviceBean after 增强  for " + jp);
   }

}
Aspect的注解方式
配置@Aspect切面
@Aspect
public class AspectAdviceBeanUseAnnotation {

   // 定义一个全局的Pointcut
   @Pointcut("execution(* edu.dongnao.courseware.spring.aop.*.do*(..))")
   public void doMethods() {
   }

   @Pointcut("execution(* edu.dongnao.courseware.spring.aop.*.service*(..))")
   public void services() {
   }

   // 定义一个Before Advice
   @Before("doMethods() and args(tk,..)")
   public void before3(String tk) {
      System.out.println("----------- AspectAdviceBeanUseAnnotation before3  增强  参数tk= " + tk);
   }

   @Around("services() and args(name,..)")
   public Object around2(ProceedingJoinPoint pjp, String name) throws Throwable {
      System.out.println("--------- AspectAdviceBeanUseAnnotation arround2 参数 name=" + name);
      System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-前增强 for " + pjp);
      Object ret = pjp.proceed();
      System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-后增强 for " + pjp);
      return ret;
   }

   @AfterReturning(pointcut = "services()", returning = "retValue")
   public void afterReturning(Object retValue) {
      System.out.println("----------- AspectAdviceBeanUseAnnotation afterReturning 增强 , 返回值为: " + retValue);
   }

   @AfterThrowing(pointcut = "services()", throwing = "e")
   public void afterThrowing(JoinPoint jp, Exception e) {
      System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强  for " + jp);
      System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强  异常 :" + e);
   }

   @After("doMethods()")
   public void after(JoinPoint jp) {
      System.out.println("----------- AspectAdviceBeanUseAnnotation after 增强  for " + jp);
   }

   /*
    * BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor
    * InstantiationAwareBeanPostProcessor Bean实例创建前后 BeanPostProcessor
    */
}
开启方式
Xml 开启@Aspectj注解

Xml中aop:aspectj-autoproxy</aop:aspectj-autoproxy> 注意了解它的属性、及子元素:指定AOP的过滤

<?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:context="http://www.springframework.org/schema/context"
    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/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

   <bean id="BeanQ" class="edu.dongnao.courseware.spring.aop.BeanQ" />

   <bean id="aspectAdviceBeanUseAnnotation" class="edu.dongnao.courseware.spring.aop.AspectAdviceBeanUseAnnotation" />

   <aop:aspectj-autoproxy>
      <!--只有符合名字表达式的bean才会进行代理创建-->
      <!--<aop:include name="thisBean" />-->
   </aop:aspectj-autoproxy>

</beans>
注解开启@Aspectj注解
@Configuration
@EnableAspectJAutoProxy //注解开启
public class AppConfig {
    
}

Advice接口体系

image-20241223102051708

PointCut接口体系

image-20241223102454019

Advisor接口体系

image-20241223102558708

JointPoint接口体系

JointPoint结构

image-20241223102656311

接口体系

image-20241223102732118

Spring AOP源码分析

Spring AOP工作流程

image-20241223102833473

配置的解析过程

XML解析入口

<aop:config>
   <aop:pointcut id="doMethods" expression="execution(* edu.dongnao.courseware.spring.aop.*.do*(..))" />
   <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="doMethods" />
   <aop:advisor advice-ref="yyArroundAdvice"
      pointcut="execution(* edu.dongnao.courseware.spring.aop.*.service*(..))"/>
</aop:config >

从aop:config标签的解析开始,看解析这个标签都做了什么。

image-20241223103136178

查找aop的jar包的meta-info目录,找到对应的Handler,AopNamespaceHandler。

image-20241223103159113

/**
 * {@code NamespaceHandler} for the {@code aop} namespace.
 *
 * <p>Provides a {@link org.springframework.beans.factory.xml.BeanDefinitionParser} for the
 * {@code <aop:config>} tag. A {@code config} tag can include nested
 * {@code pointcut}, {@code advisor} and {@code aspect} tags.
 *
 * <p>The {@code pointcut} tag allows for creation of named
 * {@link AspectJExpressionPointcut} beans using a simple syntax:
 * <pre class="code">
 * &lt;aop:pointcut id=&quot;getNameCalls&quot; expression=&quot;execution(* *..ITestBean.getName(..))&quot;/&gt;
 * </pre>
 *
 * <p>Using the {@code advisor} tag you can configure an {@link org.springframework.aop.Advisor}
 * and have it applied to all relevant beans in you {@link org.springframework.beans.factory.BeanFactory}
 * automatically. The {@code advisor} tag supports both in-line and referenced
 * {@link org.springframework.aop.Pointcut Pointcuts}:
 *
 * <pre class="code">
 * &lt;aop:advisor id=&quot;getAgeAdvisor&quot;
 *     pointcut=&quot;execution(* *..ITestBean.getAge(..))&quot;
 *     advice-ref=&quot;getAgeCounter&quot;/&gt;
 *
 * &lt;aop:advisor id=&quot;getNameAdvisor&quot;
 *     pointcut-ref=&quot;getNameCalls&quot;
 *     advice-ref=&quot;getNameCounter&quot;/&gt;</pre>
 *
 * @author Rob Harrop
 * @author Adrian Colyer
 * @author Juergen Hoeller
 * @since 2.0
 */
public class AopNamespaceHandler extends NamespaceHandlerSupport {

   /**
    * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
    * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
    * and '{@code scoped-proxy}' tags.
    */
   @Override
   public void init() {
      // In 2.0 XSD as well as in 2.5+ XSDs
      registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
      registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
      registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

      // Only in 2.0 XSD: moved to context namespace in 2.5+
      registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
   }

}
Config XML的解析

ConfigBeanDefinitionParser#parse方法

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
   CompositeComponentDefinition compositeDef =
         new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
   parserContext.pushContainingComponent(compositeDef);
// 配置自动代理构造器
   configureAutoProxyCreator(parserContext, element);

   List<Element> childElts = DomUtils.getChildElements(element);
   for (Element elt: childElts) {
      String localName = parserContext.getDelegate().getLocalName(elt);
       // pointcout切点元素解析处理
      if (POINTCUT.equals(localName)) {
         parsePointcut(elt, parserContext);
      }
       // advisor通知者元素解析处理
      else if (ADVISOR.equals(localName)) {
         parseAdvisor(elt, parserContext);
      }
       // aspect方面元素解析
      else if (ASPECT.equals(localName)) {
         parseAspect(elt, parserContext);
      }
   }

   parserContext.popAndRegisterContainingComponent();
   return null;
}
configureAutoProxyCreator()
/**
 * Configures the auto proxy creator needed to support the {@link BeanDefinition BeanDefinitions}
 * created by the '{@code <aop:config/>}' tag. Will force class proxying if the
 * '{@code proxy-target-class}' attribute is set to '{@code true}'.
 * @see AopNamespaceUtils
 */
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
   AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}
registerAspectJAutoProxyCreatorIfNecessary()
public static void registerAspectJAutoProxyCreatorIfNecessary(
      ParserContext parserContext, Element sourceElement) {

   BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
         parserContext.getRegistry(), parserContext.extractSource(sourceElement));
   useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
   registerComponentIfNecessary(beanDefinition, parserContext);
}
AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary

注册AutoProxyCreator

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

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

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

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

@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)) {
        // 工厂中有配置的自动代理构造器,则与前面传递的cls构造器进行优先级对比
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            // 找cls的优先等级,这里是指AspectJAwareAdvisorAutoProxyCreator.class
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {// 优先等级大的则会被使用
                apcDefinition.setBeanClassName(cls.getName());
            }
        }
        return null;
    }
	// 如果不包含AUTO_PROXY_CREATOR_BEAN_NAME的bean定义,则构建注册一个
    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;
}

org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST

里面装了对应的自动代理创建者的优先等级信息,其实就是索引值

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);
}

当在xml中配置了aop:aspectj-autoproxy,则会选择AnnotationAwareAspectJAutoProxyCreator。

AspectJAwareAdvisorAutoProxyCreator的继承体系

image-20241223104052276

AutoProxyCreator 是一个BeanPostProcessor、还是BeanFactoryAware,还是ProxyConfig。通过BeanPostProcessor机制,它将负责创建代理对象。

AbstractAutoProxyCreator实现

image-20241223104125980

就是我们前面看到的三个不同优先等级的AutoProxyCreator。

AopConfig

AOP配置类ProxyConfig

从aop:config 元素读取配置属性proxy_target_class、expose_proxy,存放在ProxyConfig 类中。

AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary

// AspectJ自动代理构建器
public static void registerAspectJAutoProxyCreatorIfNecessary(
      ParserContext parserContext, Element sourceElement) {

   BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
         parserContext.getRegistry(), parserContext.extractSource(sourceElement));
   useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
   registerComponentIfNecessary(beanDefinition, parserContext);
}
// 属性的处理
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
    if (sourceElement != null) {
        boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
        if (proxyTargetClass) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
        boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
        if (exposeProxy) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
        }
    }
}

AopConfigUtils.forceAutoProxyCreatorToUseClassProxying

public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
   }
}
其他元素解析

ConfigBeanDefinitionParser#parse****的其他方法

pointcut、advisor、aspect解析成对应的bean定义

pointcut对应AspectJExpressionPointcut类型bean

advisor对应DefaultBeanFactoryPointcutAdvisor类型bean

aspect对应下的子元素解析,Advisor类型的bean

注解方式配置的解析

在xml中配置aop:aspectj-autoproxy/或者通过@EnableAspectJAutoProxy注解类开启。这里我们仍然通过xml中的配置来寻找入口,不难就能在AopNameSpaceHandler.init方法找到aspectj-autoproxy的解析,对应着AspectJAutoProxyBeanDefinitionParser类解析器。

AspectJAutoProxyBeanDefinitionParser
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
   // 注册方面注解自动代理构造器
	// 做的事情跟前面的config中构建AutoProxyCreator类似
    AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
    // 处理子标签include
   extendBeanDefinition(element, parserContext);
   return null;
}

	

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary的方法

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {

		BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		registerComponentIfNecessary(beanDefinition, parserContext);
	}

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
    BeanDefinitionRegistry registry, @Nullable Object source) {
	//注册一个 AnnotationAwareAspectJAutoProxyCreator 的BeanDefinition
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator是AspectJAwareAdvisorAutoProxyCreator的子类,具有AspectJAwareAdvisorAutoProxyCreator的所有功能,并且还提供对注解的支持,往容器中注入它,用来处理注解的AOP。

注解方式的切面加载

xml方式的切面信息加载在ConfigBeanDefinitionParser.parse方法中进行了解析加载,通过源码分析,发现注解方式的并没有进行解析加载,那么提出几个疑问:

Advisor、Pointcut、Aspect信息在哪里进行了加载呢?

回到AnnotationAwareAspectJAutoProxyCreator类,查找可疑的方法,带有advisor关键字的方法。

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
    // 通过父类的同名方法,加载通过xml配置方式的advisor信息
   List<Advisor> advisors = super.findCandidateAdvisors();
   // Build Advisors for all AspectJ aspects in the bean factory.
    // 加载beanFacotory中的advisor信息,
   if (this.aspectJAdvisorsBuilder != null) {
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   }
   return advisors;
}

通过父类的同名方法,加载通过xml配置方式的advisor信息

super.findCandidateAdvisors()
protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

/**
	 * Find all eligible Advisor beans in the current bean factory,
	 * ignoring FactoryBeans and excluding beans that are currently in creation.
	 * @return the list of {@link org.springframework.aop.Advisor} beans
	 * @see #isEligibleBean
	 */
public List<Advisor> findAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    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!
        //查找Advisor的bean
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Skipping currently created advisor '" + name + "'");
                }
            }
            else {
                try {
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    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;
                }
            }
        }
    }
    return advisors;
}

在看aspectJAdvisorsBuilder.buildAspectJAdvisors()获取的advisor,看下aspectJAdvisorsBuilder初始化

AnnotationAwareAspectJAutoProxyCreator#initBeanFactory方法,这个方法是在其父类AbstractAdvisorAutoProxyCreator的setBeanFactory方法中调用,这个方法是也就是初始化之前

image-20241223151145653

方法实现:

@Override
public void setBeanFactory(BeanFactory beanFactory) {
   super.setBeanFactory(beanFactory);
   if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
      throw new IllegalArgumentException(
            "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
   }
   initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
	}

AnnotationAwareAspectJAutoProxyCreator#initBeanFactory方法

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   super.initBeanFactory(beanFactory);
    // 构建切面反射的advisor工厂,用来创建ApectJ配置类型的advisors
   if (this.aspectJAdvisorFactory == null) {
      this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
   }
    // 传递了beanFactory、aspectJAdvisorFactory,实例化aspectJAdvisorsBuilder
   this.aspectJAdvisorsBuilder =
         new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
BeanFactoryAspectJAdvisorsBuilderAdapter.buildAspectJAdvisors方法

重点观察advisorFactory实例被调用的地方

/**
 * Look for AspectJ-annotated aspect beans in the current bean factory,
 * and return to a list of Spring AOP Advisors representing them.
 * <p>Creates a Spring Advisor for each AspectJ advice method.
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
/**
* 方法的逻辑:<br>
* 1、看有没有缓存下带有@Ascpect注解的Bean的名字:aspectBeanNames。<br>
* 2、没有这个缓存的名字,表示这是第一次来创建AspectJAdvisors,则获取BeanFactory中所有的beanNames;<br>
* 遍历beanNames,获取每个beanName对应的Class,看它上面有没有@Aspect注解,有则提前它里面的注解advice,创建Advisor;
* <br>
* 并缓存下创建的Advisor,缓存记录BeanName,返回Advisor <br>
* 3、有这个缓存表示已经创建过了,则直接从缓存中获取缓存的Advisor,返回。
*/
public List<Advisor> buildAspectJAdvisors() {
   List<String> aspectNames = this.aspectBeanNames;
	// 刚开始为null,查找所有的切面bean的名字,并且实例化返回
   if (aspectNames == null) {
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List<Advisor> advisors = new ArrayList<>();
            aspectNames = new ArrayList<>();
             //获取所有的bean定义的名字
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            for (String beanName : beanNames) {
               if (!isEligibleBean(beanName)) {
                  continue;
               }
               // 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.
               Class<?> beanType = this.beanFactory.getType(beanName);
               if (beanType == null) {
                  continue;
               }
                // 判断是否为一个切面配置,@Aspect注解
               if (this.advisorFactory.isAspect(beanType)) {
                  aspectNames.add(beanName);
                  AspectMetadata amd = new AspectMetadata(beanType, beanName);
                   // 单例模式的advisor
                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                     MetadataAwareAspectInstanceFactory factory =
                           new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                      
                      //重点: 解析并构建获得advisor列表
                     List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                      
                      // xml配置aspect bean范围,或者@Aspect中配置bean范围
					// 如果bean本身是单例的,则缓存创建的advisors,advisor就是单例方式
					// 如果bean不是单例的,则缓存advisor的factory,advisor也就不是单例的
                     if (this.beanFactory.isSingleton(beanName)) {
                         // 单例advisor缓存起来
                        this.advisorsCache.put(beanName, classAdvisors);
                     }
                     else {
                             // 非单例,缓存工厂
                        this.aspectFactoryCache.put(beanName, factory);
                     }
                     advisors.addAll(classAdvisors);
                  }
                  else {
                      // 非单例模式advisor处理
                  
                     // Per target or per this.
                     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();
   }
    // 再次执行,从缓存获取
   List<Advisor> advisors = new ArrayList<>();
   for (String aspectName : aspectNames) {
       // 单例advisor从缓存获取,非单例由advisor工厂再次构建获得
      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;
}
ReflectiveAspectJAdvisorFactory.getAdvisors
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
   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 ArrayList<>();
    // 加载构建advisor
   for (Method method : getAdvisorMethods(aspectClass)) {
      // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
      // to getAdvisor(...) to represent the "current position" in the declared methods list.
      // However, since Java 7 the "current position" is not valid since the JDK no longer
      // returns declared methods in the order in which they are declared in the source code.
      // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
      // discovered via reflection in order to support reliable advice ordering across JVM launches.
      // Specifically, a value of 0 aligns with the default value used in
      // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
      Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, 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.
   for (Field field : aspectClass.getDeclaredFields()) {
      Advisor advisor = getDeclareParentsAdvisor(field);
      if (advisor != null) {
         advisors.add(advisor);
      }
   }

   return advisors;
}

主要实现在ReflectiveAspectJAdvisorFactory#getAdvisor方法

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

   validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
	// 获得切点
   AspectJExpressionPointcut expressionPointcut = getPointcut(
         candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
   if (expressionPointcut == null) {
      return null;
   }
	// 实例化一个advisor
   return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
         this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

再看看getPointcut、getAdvice方法。

什么时候加载?

我们找到的这个方法对不对?在什么时候加载?我们在ReflectiveAspectJAdvisorFactory.getAdvisors 方法上打上断点,进行一波调试,查看调用堆栈信息。

// 断点地方
getAdvisors(MetadataAwareAspectInstanceFactory):120,
ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
buildAspectJAdvisors():110, BeanFactoryAspectJAdvisorsBuilder
(org.springframework.aop.aspectj.annotation)
findCandidateAdvisors():95, AnnotationAwareAspectJAutoProxyCreator
(org.springframework.aop.aspectj.annotation)
shouldSkip(Class, String):101, AspectJAwareAdvisorAutoProxyCreator
(org.springframework.aop.aspectj.autoproxy)
postProcessBeforeInstantiation(Class, String):251, AbstractAutoProxyCreator
(org.springframework.aop.framework.autoproxy)
// 在bean对象实例化之前的BenPostProcessor,即InstantiationAwareBeanPostProcessor
applyBeanPostProcessorsBeforeInstantiation(Class, String):1140,
AbstractAutowireCapableBeanFactory
(org.springframework.beans.factory.support)
resolveBeforeInstantiation(String, RootBeanDefinition):1113,
AbstractAutowireCapableBeanFactory
(org.springframework.beans.factory.support)
createBean(String, RootBeanDefinition, Object[]):505,
AbstractAutowireCapableBeanFactory
(org.springframework.beans.factory.support)
lambda$doGetBean$0(String, RootBeanDefinition, Object[]):324,
AbstractBeanFactory (org.springframework.beans.factory.support)
getObject():-1, 943870983
(org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$45)
getSingleton(String, ObjectFactory):226, DefaultSingletonBeanRegistry
(org.springframework.beans.factory.support)
doGetBean(String, Class, Object[], boolean):322, AbstractBeanFactory
(org.springframework.beans.factory.support)
getBean(String):202, AbstractBeanFactory
(org.springframework.beans.factory.support)
preInstantiateSingletons():897, DefaultListableBeanFactory
(org.springframework.beans.factory.support)
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):879,
AbstractApplicationContext (org.springframework.context.support)
refresh():551, AbstractApplicationContext
(org.springframework.context.support)
<init>(String[]):71, GenericXmlApplicationContext
(org.springframework.context.support)
main(String[]):8, AopMainUseAspectAnnotation
(edu.dongnao.courseware.spring.aop)

可以得知,在IOC容器初始化刷新里提前创建单例bean的流程中,单例bean实例化之前进行加载解析。

ans.factory.support)
lambda$doGetBean 0 ( S t r i n g , R o o t B e a n D e f i n i t i o n , O b j e c t [ ] ) : 324 , A b s t r a c t B e a n F a c t o r y ( o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . s u p p o r t ) g e t O b j e c t ( ) : − 1 , 943870983 ( o r g . s p r i n g f r a m e w o r k . b e a n s . f a c t o r y . s u p p o r t . A b s t r a c t B e a n F a c t o r y 0(String, RootBeanDefinition, Object[]):324, AbstractBeanFactory (org.springframework.beans.factory.support) getObject():-1, 943870983 (org.springframework.beans.factory.support.AbstractBeanFactory 0(String,RootBeanDefinition,Object[]):324,AbstractBeanFactory(org.springframework.beans.factory.support)getObject():1,943870983(org.springframework.beans.factory.support.AbstractBeanFactory$Lambda$45)
getSingleton(String, ObjectFactory):226, DefaultSingletonBeanRegistry
(org.springframework.beans.factory.support)
doGetBean(String, Class, Object[], boolean):322, AbstractBeanFactory
(org.springframework.beans.factory.support)
getBean(String):202, AbstractBeanFactory
(org.springframework.beans.factory.support)
preInstantiateSingletons():897, DefaultListableBeanFactory
(org.springframework.beans.factory.support)
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):879,
AbstractApplicationContext (org.springframework.context.support)
refresh():551, AbstractApplicationContext
(org.springframework.context.support)
(String[]):71, GenericXmlApplicationContext
(org.springframework.context.support)
main(String[]):8, AopMainUseAspectAnnotation
(edu.dongnao.courseware.spring.aop)


可以得知,在IOC容器初始化刷新里提前创建单例bean的流程中,单例bean实例化之前进行加载解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值