spring aop 分析

算法流光使
• 阅读 1096

一、生成代理对象

spring对象初始化过程(忘记了可以看这里:对象初始化常规流程),属性赋值后对对象做代理增强——这是AOP得以实现的基础

源码入口如下:

Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
    // 属性赋值方法
    populateBean(beanName, mbd, instanceWrapper);
    // ## 此处做代理增强
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}

我们看下方法实现:

initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // 对象初始化前置处理器
    wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    
    // 执行初始方法
    this.invokeInitMethods(beanName, wrappedBean, mbd);
    
    // ## 对象初始化后置处理器
    wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

跟踪后置处理器的执行链路:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // ## 1.获取Advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

    // ## 2.创建AOP代理对象
    Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
}

分别观察这两步的实现。

1.获取Advisor

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
// 我们观察“注解实现”
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

List<Advisor> buildAspectJAdvisors() {
    Class<?> beanType = this.beanFactory.getType(beanName);
    // ### A.什么样的对象是Advisor?
    if (this.advisorFactory.isAspect(beanType)) {
        // ### B.Advisor对象如何创建
        List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
    }
}

从这部分源码又衍生出几个问题。

A.什么样的对象是Advisor

答:被@Aspect对象修饰的对象是Advisor

org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect
org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#hasAspectAnnotation

private boolean hasAspectAnnotation(Class<?> clazz) {
    // 源码是这么写的
    return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

再思考一下,使用过程中被@Aspect注解修饰的对象是什么?

答案是“一个切面声明”,比如下面的例子。

#### 这是一个切面声明的例子,非spring源码 ####

@Aspect
@Component
public class TransactionAop {
    @Pointcut("execution(* com.jiuxian..service.*.*(..))")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void beginTransaction() {
        System.out.println("before beginTransaction");
    }
    
    @After("pointcut()")
    public void commit() {
        System.out.println("after commit");
    }
}

于是大胆推断——Advisor是不是一个切面对象的封装?

接下来,通过Advisor的创建过程来验证这个推断是否正确。

B.Advisor对象如何创建

org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory){
    // ** 代码1:获取了某种方法 **
    for (Method method : getAdvisorMethods(aspectClass)) {
        // ** 代码2:根据`代码1`的方法构建Advisor **
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
    }
}

代码1:获取的某种方法是什么?

ReflectionUtils.doWithMethods(aspectClass, method -> {
  // 获取非@Poincut注解修饰的所有方法(即@Before、@After注解修饰的方法)
  if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
      methods.add(method);
  }
});

代码2:根据代码1的方法构建的Advisor到底是什么?

org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor

Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {
        // == 获取切面信息
        AspectJExpressionPointcut expressionPointcut = getPointcut(
                candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {
            return null;
        }

        // == 返回Advisor的实现
        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

Advisor由InstantiationModelAwarePointcutAdvisorImpl实现,结合代码1来看,Advisor本质是对一个切面方法(@Before、@After等修饰的方法)的封装

之前的推断有些许偏差……

最后我们看一下InstantiationModelAwarePointcutAdvisorImpl是怎么获取Advice的

C.Advisor获取Advice

org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#getAdvice
org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice

// == 每个注解都对应着一种具体的Advice实现
switch (aspectJAnnotation.getAnnotationType()) {
    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;
}        

2.创建AOP代理对象

前面纵深过大,简单总结一下:
我们用大段篇幅解释了wrapIfNecessary方法的“代码1”部分——这个specificInterceptors数组,其实就是切面中的切面方法(各种@Before、@After注解修饰的方法)的封装。

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // ## 1.获取Advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

    // ## 2.创建AOP代理对象
    Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
}

接下来,进入“代码2”部分,看看AOP代理是如何创建的!

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
    //== A.先创建AopProxy对象,本质就是new JdkDynamicAopProxy(config)
   return new JdkDynamicAopProxy(config)
                //== B.再调用JdkDynamicAopProxy的getProxy()方法
               .getProxy(classLoader);
}
public Object getProxy(@Nullable ClassLoader classLoader) {
    // ## 第三个参数InvocationHandler传入的是this,所以被代理对象实际执行的是本类的invoke()方法
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

代理执行逻辑,下一章再分析。

二、AOP执行

目前我们已经知道,spring对象初始化后会对声明AOP切面的对象作动态代理

这样在对象方法执行时,会执行相应的代理方法。
而代理对象又包含全部的切面方法封装和切面声明,剩下的只是把它们关联起来。

本章对这部分逻辑加以分析。

// ## 1.构建责任链(全部的advice)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// ## 2.责任链调度
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, 
            args, targetClass, chain);
retVal = invocation.proceed();

1.构建责任链

org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice

if (advisor instanceof PointcutAdvisor) {
    PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
    if (config.isPreFiltered() 
        || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
        // 获取方法匹配器@Pointcut的expression
        MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
        boolean match;
        // 根据expression表达式匹配目标方法(当前执行的方法)
        match = mm.matches(method, actualClass);

        if (match) {
            // 匹配上了,返回方法的全部拦截器(advice的封装)
            MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }
}

2.责任链调度

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
// 构造函数中赋值chain,方法拦截器 -> advice
protected final List<?> interceptorsAndDynamicMethodMatchers;
// chain的索引
private int currentInterceptorIndex = -1;

--------  ## 以上为属性 ##  --------------

// ### 这是一个递归方法
public Object proceed() throws Throwable {
    // == 1.已经是chain中的最后一个拦截器,则执行原方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return this.invokeJoinpoint();
    } 
    // == 2.否则,执行过滤器方法
    else {
        // 索引自增,获取链中的当前拦截器
        Object interceptorOrInterceptionAdvice 
            = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        
        // ## 拦截器执行(不同的拦截器有不同的实现)
        return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
    }
}

最后观察两种不同的拦截器实现吧。

  • before拦截器

    // == before拦截器(通知)
    org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke
    {    
      // 先执行拦截器
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
      // 再执行方法(递归调用,代码去执行ReflectiveMethodInvocation#proceed)
      return mi.proceed();
    }
  • after拦截器

    // == after拦截器(通知)
    org.springframework.aop.aspectj.AspectJAfterAdvice#invoke
    {
      Object var2;
      try {
          // 先执行方法(递归调用,代码去执行ReflectiveMethodInvocation#proceed)
          var2 = mi.proceed();
      } finally {
          // 再执行拦截器实现
          this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
      }
      return var2;
    }

附录

P6-P7知识合辑

点赞
收藏
评论区
推荐文章
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
java面试题:Spring
Spring面试时,最好能结合底层代码说出IOC,AOP或SpringMVC的流程,能说出拦截器的底层。如果看过Spring的源码,并能结合设计模式表达,是很大的加分项。IOCQ:讲一下IOCIOC是"控制反转"。IOC将对象的控制权进行分离,交由第三方进行控制。IOC容器负责创建对象,管理对象.详情参见:https:/
0源码基础学习Spring源码系列(二)——Spring如何解决循环依赖
本篇文章适用于0基础学习spring源码,文章重点解析spring如何解决循环依赖,并从解决循环依赖过程、三级缓存在循环依赖中的作用、解决代理对象的问题、二级缓存、初始化几个维度出发,解析spring源码。
Wesley13 Wesley13
3年前
Java项目笔记之知识点总结03
不点蓝字,我们哪来故事?SSM本质是Spring去集成SpringMVC和MyBatis,即控制器对象、业务对象、Mapper对象等都交由Spring容器管理,使用SpringIoC和DI来完成对象创建及其属性注入,使用AOP来配置事务。作用是在框架上基础上开发,发挥各
Stella981 Stella981
3年前
Spring3.1.0实现原理分析(九).AOP之创建代理对象的过程
    大家好,今天我会用一个例子来讲解Spring创建bean代理对象的过程,为大家揭开SpringAOP的神秘面纱。在看这篇博客前我强烈建议读者先看下这两篇博客《Spring3.1.0实现原理分析(六).实例化》(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fhttp%2F
Easter79 Easter79
3年前
Spring的两种代理JDK和CGLIB的区别浅谈
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Easter79 Easter79
3年前
Spring的Aop调用当前类的两种方法
我们知道Spring对于AOP实现有两种方法,如果类是接口实现类,则采用JDK动态代理实现AOP。如果类没有实现接口,则采用cglib生成子类做增强,以实现代理类的目的,其实运行时找到的是这个代理类,而不是原类。所以在一个代理类中调用内部的方法,是不是再走AOP逻辑的,那有什么好的方法可以解决这种问题吗?基于上面的思路有两种解决办法方法一:直接从
Stella981 Stella981
3年前
Spring Bean 生命周期回调
Spring生命周期回调说明如果只是简单的对象初始化,我们可以将其放到构造器中处理;如果是对注入的类或者帮助类做一些初始化处理,可以考虑使用初始化方法。Spring提供了很多的扩展点,其中就有生命周期回调,我们可以在bean初始化之前做一些处理,在bean销毁之前做一些处理。早期Spring生命周期扩展方式Initializ
Stella981 Stella981
3年前
SpringAOP源码跟踪及学习
Spring版本4.3.2在拿到Bean实例以后,会经历一系列的初始化工作,如:工厂回调、init方法、后处理器在Bean初始化前后的处理等,在一般情况下(非factorymethod创建的Bean等),AOP代理对象的创建就在后处理器的处理方法中实现。入口以AbstractAutowireCapableB
Easter79 Easter79
3年前
Spring的两种动态代理:Jdk和Cglib 的区别和实现
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Easter79 Easter79
3年前
Spring知识点提炼
1\.Spring框架的作用清理:Spring是轻量级的,基本的版本大小为2MB控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。面向切面的编程AOP:Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。容器:Spring包含并管理应用中对象