Spring Aop 源码解读

我们在学习Spring Aop 源代码前,我们回忆一下在我们的工作中我们在哪些场景下需要用到代理?是怎么个代理法?我们是怎么个使用法就达到了我们想要的目的?下面我们就来一起回忆一下:

1 我们有这样一些需求,希望在目标方法的前后执行一些代码,这些代码不是固定放置的,而是动态织入的,比如:

// 业务处理前做一些事情
doSomeThingBeforeBusiness(); // 动态织入

// 业务处理
public void business() {} // 目标方法

// 业务处理后做一些事情
doSomeThingAfterBusiness(); // 动态织入

2 有了目标需求后,接下来要想的是我们通过什么方式可以把我们在其他地方声明的代码如愿的织入到目标方法的前后执行或者想要的时间点执行,所谓的其他代码在哪里声明了?我们想到的是通过下面代码那样所示来表示一个切面的声明,告诉执行程序哪些是要织入的代码,如@Before注解、@AfterReturning注解就是干这个事的。同时也要告诉执行程序代码的织入是有条件的,不是随便哪个目标上都去织入代码的,如@Pointcut注解就是干这个事的。

@AspectJ
public class BusinessAspect {

    @PointCut( value = "execution(com.hehui.**.business(**))" ) // 告诉执行程序哪些目标需要织入代码
    public void defPointcut() {

    }

    @Before("defPointcut()") // 在目标对象前织入的具体代码
    public void doSomeThingBeforeBusiness(JoinPoint joinPoint) {

    }

    @AfterReturning("defPointcut()") // 在目标对象后织入的具体代码
    public void doSomeThingAfterBusiness(JoinPoint joinPoint) {

    }
}

结合以上的需求和声明式的使用方式,最终执行程序生成的代码结构类似以下这样:

// 生成的代理方法

public void proxyMethod() {

    // 业务处理前做一些事情
    doSomeThingBeforeBusiness(); // 动态织入

    // 业务处理
    public void business() {} // 这是目标方法

    // 业务处理后做一些事情
    doSomeThingAfterBusiness(); // 动态织入

}

当我们调用原始对象的business()方法时就会被代理对象的 proxyMethod()方法所代理,这样就达到了我们的目的。

3 有了需求也有了具体怎么使用的方案,接下来就是思考和设计怎么落地的问题了,然 Spring Aop 采用的就是这种方案来实现的,那么我们就来学习和研究 Spring Aop 具体是怎么设计的,具体代码又是怎么实现的。

我认为:做任何事情要是脱离了目的性就都是盲目的,解决任何一个需求要是脱离了具体怎么个使用法就都是抽象的,解决方案要是脱离了具体怎么个落地法就都是空想的。只有把“目的性、具体怎么使用、具体怎么落地”结合起来才是唯物的工作作风。无的放矢的学习是没有意义的,有的放矢的学习才是实事求是的态度。

目录

一、学习前的疑问?

二、学习源代码

2.1 代理对象创建的整个过程的源代码解读

2.2 @AspectJ 声明的切面类解析成Advisor 切面对象的整个过程的源代码解读

2.3 切面对象 Advisor 适配成 MethodInterceptor 方法拦截器对象的整个过程的源代码解读

2.4 MethodInterceptor 方法拦截器链调用的整个过程的源代码解读

2.5 切面、切点、通知、连接点等源代码解读

三、学习后的总结

3.1 Spring Aop 用代码的形式如何声明一个切面?

3.2 Spring Aop 声明的 @AspectJ 切面类是在什么时候解析成 Advisor 切面对象的?

3.3 Spring Aop  切面对象 Advisor 又是在什么时候适配成 MethodInterceptor 方法拦截器对象的?

3.4 Spring Aop 方法拦截器 MethodInterceptor 是在什么时候调用的?又是如何调用的?

3.5 把以上问题搞清楚了后我们就来总结 Spring Aop 中所谓的切面、切点、通知、连接点都是些什么东西?用代码是怎么表示的,他们间的关系结构是什么样的?


一、学习前的疑问?

1.1 Spring Aop 用代码的形式如何声明一个切面?

1.2 Spring Aop 使用@AspectJ注解声明的切面类是在什么时候解析成Advisor切面对象的?

1.3 Spring Aop  切面对象Advisor又是在什么时候适配成MethodInterceptor方法拦截器对象的?

1.4 Spring Aop 方法拦截器对象MethodInterceptor是在什么时候调用的?又是如何调用的?

1.5 把以上问题搞清楚了后我们就来总结 Spring Aop 中所谓的切面、切点、通知、拦截器、连接点都是些什么东西?用代码是怎么表示的,他们间的关系结构是什么样的?

二、学习源代码
2.1 代理对象创建的整个过程的源代码解读

我在getBean()方法的源代码解读这篇文章中已经讲解了Bean的创建过程,并且也提到了Bean对象的代理对象创建是通过 BeanPostProcessor 这个接口来进行扩展的,我们只要找到这个实现了代理对象创建的这么一个 BeanPostProcessor 具体的实现类就能找到入口了,然而我们通过这种思路去找的过程中,就找到了一个类为 AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator extends ProxyProcessorSupport extends ProxyConfig,其中 AbstractAutoProxyCreator 这个类就实现了 BeanPostProcessor 接口,下面我们就从 AbstractAutoProxyCreator 类中的 postProcessAfterInitialization() 方法为入口开始进行这一章节点的源代码解读

AbstractAutoProxyCreator 类中的 postProcessAfterInitialization() 方法的具体代码如下所示:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

        // 这是bean初始化的一个后置处理钩子方法

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

        

        // 根据这个方法的名称,我们就可以猜想:如果有必要就进行包装

        protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
                ...省略一些代码
                // Create proxy if we have advice.

                // 上面英文翻译过来的意思是:如果能够拿到通知,就创建一个代理

                // 获取当前bean有没有通知需要被应用
                Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, 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;
        }

        // 这个方法返回一个代理对象

        protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
                @Nullable Object[] specificInterceptors, TargetSource targetSource) {
                ...省略一些代码
                ProxyFactory proxyFactory = new ProxyFactory();
                ...省略一些代码

                // 这个方法是把通知全部适配成或者包装成 Advisor对象
                Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
                proxyFactory.addAdvisors(advisors);
                ...省略一些代码
                return proxyFactory.getProxy(getProxyClassLoader());
        }        
}

由上面红色字体createProxy()方法中的代码可知,代理对象的创建是交给ProxyFactory类的getProxy()方法来实现的,其代码如下所示:

public class ProxyFactory extends ProxyCreatorSupport {
    ...省略一些代码
    public Object getProxy(@Nullable ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }
    ...省略一些代码
}

public class ProxyCreatorSupport extends AdvisedSupport {

    private AopProxyFactory aopProxyFactory;
    ...省略一些代码
    public ProxyCreatorSupport() {
        this.aopProxyFactory = new DefaultAopProxyFactory();
    }

    public AopProxyFactory getAopProxyFactory() {
        return this.aopProxyFactory;
    }

    ...省略一些代码

    protected final synchronized AopProxy createAopProxy() {
        ...省略一些代码
        return getAopProxyFactory().createAopProxy(this);
    }
    ...省略一些代码
}

根据上面代码可知,代理对象的创建是交给DefaultAopProxyFactory类的createAopProxy()方法来实现的,其代码如下所示:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            ...省略一些代码
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        } else {
            return new JdkDynamicAopProxy(config);
        }
    }
    ...省略一些代码
}

由上面的代码我们可以知道 createAopProxy()方法要么返回一个JdkDynamicAopProxy类实例,要么返回一个ObjenesisCglibAopProxy类实例,根据上面的红色字体getProxy()方法所示那样,我们还要继续调用JdkDynamicAopProxy类的getProxy()方法或者ObjenesisCglibAopProxy类的getProxy()方法,才是最终返回了一个代理对象,至此代理对象的创建过程也就到此就结束了。接下来我们再来分别看看JdkDynamicAopProxy类的getProxy()方法和ObjenesisCglibAopProxy类的getProxy()方法具体是怎么实现的,我们先来看看JdkDynamicAopProxy​​​​​​​类的getProxy()方法,其代码如下所示:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
  
  // 返回代理对象
  public Object getProxy(@Nullable ClassLoader classLoader) {
    ...省略一些原代码

    // 使用JDK动态代理的方式创建一个代理对象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  }

  被代理对象的方法调用都会经过invoke方法拦截,invoke方法核心代码如下所示:
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   ...省略一些原代码
   try {
      ...省略一些原代码
      Object retVal;
      // Get the interception chain for this method.

      // 这个方法的职责是把 Advisor 对象适配成 Interceptor对象,并形成一个链返回
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      if (chain.isEmpty()) {         
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {         
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         retVal = invocation.proceed();
      }
...省略一些原代码
   }
   finally {
      ...省略一些原代码
   }
  }
}

我们再来看看ObjenesisCglibAopProxy​​​​​​​类的getProxy()方法,其代码如下所示:

class ObjenesisCglibAopProxy extends CglibAopProxy implements AopProxy, Serializable {

        // 这个方法是使用CGLIB库来生成代理对象

        public Object getProxy(@Nullable ClassLoader classLoader) {
        try {
            ...省略一些代码
            // Configure CGLIB Enhancer...
            Enhancer enhancer = createEnhancer();
            ...省略一些代码

            Callback[] callbacks = getCallbacks(rootClass);
            ...省略一些代码
            // Generate the proxy class and create a proxy instance.
            return createProxyClassAndInstance(enhancer, callbacks);
        }
        ...省略一些代码
    }

    // 返回一个代理对象
    protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
        enhancer.setInterceptDuringConstruction(false);
        enhancer.setCallbacks(callbacks);
        return (this.constructorArgs != null && this.constructorArgTypes != null ?
        enhancer.create(this.constructorArgTypes, this.constructorArgs) :
        enhancer.create());
    }

    // 给代理对象添加一些拦截器
    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        ...省略一些代码
        Callback[] callbacks;
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap<>(methods.length);

            // TODO: small memory optimization here (can skip creation for methods with no advice)
            for (int x = 0; x < methods.length; x++) {
                Method method = methods[x];

                // 这个方法的职责是把 Advisor 对象适配成 Interceptor对象,并形成一个链返回
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
                // FixedChainStaticTargetInterceptor这个拦截器非常重要,拦截器链的调用就是通过这个入口拦截器开始调用的

                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(method, x);
             }
            callbacks = fixedCallbacks;
            ...省略一些代码
        }                
        ...省略一些代码
        return callbacks;
    }
}

至此,代理对象的创建过程解读完毕

2.2 @AspectJ 声明的切面类解析成Advisor 切面对象的整个过程的源代码解读

@AspectJ声明的切面类解析成切面对象Advisor这个过程是在创建代理对象之前完成的,如下面红色字体的 getAdvicesAndAdvisorsForBean()方法就是干这个事情的,具体代码如下所示:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

        // 这是bean初始化的一个后置处理钩子方法

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

        

        // 根据这个方法的名称,我们就可以猜想:如果有必要就进行包装

        protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
                ...省略一些代码
                // Create proxy if we have advice.

                // 上面英文翻译过来的意思是:如果能够拿到通知,就创建一个代理

                // 获取当前bean有没有通知需要被应用
                Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, 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;
        }

        protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {
                ...省略一些代码
                ProxyFactory proxyFactory = new ProxyFactory();
                ...省略一些代码
                Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
                proxyFactory.addAdvisors(advisors);
                ...省略一些代码
                return proxyFactory.getProxy(getProxyClassLoader());
        }
        // 这个方法返回所有合格的通知

        protected Object[] getAdvicesAndAdvisorsForBean(
                Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
                List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
                ...省略
        }
        protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {

                // 查找候选的切面
                List<Advisor> candidateAdvisors = findCandidateAdvisors();
                ...省略代码
                return eligibleAdvisors;
        }
}

findCandidateAdvisors() 这个方法在 AnnotationAwareAspectJAutoProxyCreator 类中被重写,代码如下所示:

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
    ...省略
        private AspectJAdvisorFactory aspectJAdvisorFactory;
    private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
    protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        super.initBeanFactory(beanFactory);
        if (this.aspectJAdvisorFactory == null) {           
            this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
        }

        // 这个对象负责把 @AspectJ 注解声明的切面类解析成 Advisor 对象
        this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
    }

    // 这个方法负责查找候选的切面对象
    protected List<Advisor> findCandidateAdvisors() {
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        if (this.aspectJAdvisorsBuilder != null) {

            // 这个地方就是把 @AspectJ 注解声明的切面 解析成 Advisor 切面对象的入口
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
    }
        ...省略
}

由上面代码可知,获取由@AspectJ注解声明的切面工作是由 BeanFactoryAspectJAdvisorsBuilderAdapter类的buildAspectJAdvisors()方法来实现的,其代码如下:

private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {}

public class BeanFactoryAspectJAdvisorsBuilder {
        private final ListableBeanFactory beanFactory;
        private final AspectJAdvisorFactory advisorFactory;

        

        public List<Advisor> buildAspectJAdvisors() {
                List<String> aspectNames = this.aspectBeanNames;

                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;
                                                }
                
                                                Class<?> beanType = this.beanFactory.getType(beanName, false);
                                                if (beanType == null) {
                                                    continue;
                                                }

                                                // 如果这个bean类上有 @AspectJ注解,就说明这个是一个切面
                                                if (this.advisorFactory.isAspect(beanType)) {
                                                        aspectNames.add(beanName);
                                                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                                                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                                                MetadataAwareAspectInstanceFactory factory =
                                                                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                                                        // 把 @AspectJ 声明的切面解析成 Advisor 并返回

                                                                        List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                                                if (this.beanFactory.isSingleton(beanName)) {
                                                                    this.advisorsCache.put(beanName, classAdvisors);
                                                                }
                                                                else {
                                                                    this.aspectFactoryCache.put(beanName, factory);
                                                                }
                                                                advisors.addAll(classAdvisors);

                                                        }
                                                 } 

                                        }

                                }

                    } 

        }
        protected boolean isEligibleBean(String beanName) {
            return true;
        }

}

由上面代码可知,获取由@AspectJ注解声明的切面工作是由 ReflectiveAspectJAdvisorFactory类的getAdvisors()方法来实现的,其代码如下:

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
    ...省略
    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
        Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
        validate(aspectClass);
        MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
        new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
        List<Advisor> advisors = new ArrayList<>();
        // 获取@AspectJ注解声明的这个类里面除了没有@PointCut注解的所有方法,进行遍历
        for (Method method : getAdvisorMethods(aspectClass)) {
            // 根据方法适配成 Advisor
            Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
                ...省略
        return advisors;
    }
    private List<Method> getAdvisorMethods(Class<?> aspectClass) {
        final List<Method> methods = new ArrayList<>();
        ReflectionUtils.doWithMethods(aspectClass, method -> {
            // Exclude pointcuts

            // 不包含 @Pointcut注解声明的方法
            if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                methods.add(method);
            }
        }, ReflectionUtils.USER_DECLARED_METHODS);
        if (methods.size() > 1) {
            methods.sort(METHOD_COMPARATOR);
        }
        return methods;
    }

    // 返回一个切面对象
    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);
    }

    // 返回一个切点对象
    private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        findAspectJAnnotationOnMethod() 这个方法里面只会返回方法上有@Around, @Before, @After, @AfterReturning, @AfterThrowing注解的方法,要是方法上没有这些注解则返回Null

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

        // 创建一个切点
        AspectJExpressionPointcut ajexp =
        new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
        // 设置切点表达式

        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        if (this.beanFactory != null) {
            ajexp.setBeanFactory(this.beanFactory);
        }
        return ajexp;
    }
    ...省略

至此,@AspectJ 声明的切面类解析成Advisor 切面对象的整个过程的源代码解读到此结束。

2.3 切面对象 Advisor 适配成 MethodInterceptor 方法拦截器对象的整个过程的源代码解读

从上面对创建代理对象的过程的源代码解读中我们看到不管是JdkDynamicAopProxy类的getProxy()方法​​​​​​​创建代理对象还是ObjenesisCglibAopProxy类的getProxy()方法​​​​​​​创建代理对象,其中都有这么一行代码 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 没错就是这行代码的 getInterceptorsAndDynamicInterceptionAdvice()这个方法把切面Advisor对象适配成MethodInterceptor方法拦截器对象的,而this.advised这个属性对应的类就是AdvisedSupport,那么我们就从AdvisedSupport类的getInterceptorsAndDynamicInterceptionAdvice()方法为入口开始对切面对象 Advisor 适配成 MethodInterceptor 方法拦截器对象的整个过程的源代码进行解读,其代码如下所示:

public class AdvisedSupport extends ProxyConfig implements Advised {

        AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

    

        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
                MethodCacheKey cacheKey = new MethodCacheKey(method);
                List<Object> cached = this.methodCache.get(cacheKey);
                if (cached == null) {
                        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                        this, method, targetClass);
                        this.methodCache.put(cacheKey, cached);
                }
                return cached;
        }

由以上代码我们可以知道,切面对象 Advisor 适配成 MethodInterceptor 方法拦截器对象的工作是交给DefaultAdvisorChainFactory类的getInterceptorsAndDynamicInterceptionAdvice()方法来实现的,其代码如下所示:

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        // 拿到所有切面对象

        Advisor[] advisors = config.getAdvisors();
        List<Object> interceptorList = new ArrayList<>(advisors.length);
        ...省略一些代码
        for (Advisor advisor : advisors) {
            ...省略一些代码

            // 把所有切面对象适配成Interceptor对象
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
        return interceptorList;
    }
}

public final class GlobalAdvisorAdapterRegistry {
    private GlobalAdvisorAdapterRegistry() {}

    private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();

    public static AdvisorAdapterRegistry getInstance() {
         return instance;
    }
}

由以上代码我们可以知道,切面对象 Advisor 适配成 MethodInterceptor 方法拦截器对象的工作是交给DefaultAdvisorAdapterRegistry类的getInterceptors()方法来实现的,其代码如下所示:

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

    private final List<AdvisorAdapter> adapters = new ArrayList<>(3);

    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
    ...省略一些代码

    // 这个方法是把切面对象 Advisor 适配成 拦截器对象 MethodInterceptor的最底层的具体实现
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[0]);
    }
    ...省略一些代码
}

至此,切面对象 Advisor 适配成 MethodInterceptor 方法拦截器对象的整个过程的源代码解读到此结束。

2.4 MethodInterceptor 方法拦截器链调用的整个过程的源代码解读

我们想要搞清楚拦截器链的调用是在哪里调用的,又是怎么调用的这个问题,我们只要找到代理对象拦截调用的入口方法就可以了,根据上面对创建代理对象的源码解读中我们知道代理对象的创建有两种实现,一种是基于JDK的动态代理创建代理对象,另一种是基于CGLIb库动态生成代理对象,然而通过JDK的动态代理创建代理对象后是通过实现InvocationHandler接口的invoke()方法来做入口拦截的,通过CGLIb库动态代理创建代理对象后是通过添加了一个入口拦截器来做入口拦截的,这个入口拦截器类为 FixedChainStaticTargetInterceptor,接下来分别来解读下这两种代理入口方法的具体实现,先来解读JDK的动态代理拦截入口方法,其代码如下所示:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
  
  // 返回代理对象
  public Object getProxy(@Nullable ClassLoader classLoader) {
    ...省略一些原代码

    // 使用JDK动态代理的方式创建一个代理对象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  }

  被代理对象的方法调用都会经过invoke方法拦截,invoke方法核心代码如下所示:
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   ...省略一些原代码
   try {
      ...省略一些原代码
      Object retVal;
      // Get the interception chain for this method.

      // 这个方法的职责是把 Advisor 对象适配成 Interceptor对象,并形成一个链返回
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      if (chain.isEmpty()) {         
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {    

        // 把代理对象、目标对象、目标方法、方法参数和拦截器链封装到一个ReflectiveMethodInvocation对象中    
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

         // 开始链式调用
         retVal = invocation.proceed();
      }
...省略一些原代码
   }
   finally {
      ...省略一些原代码
   }
  }
}

由以上代码可以知道,invoke()方法里面主要是干了两件事情,第一件事情把切面对象Advisor适配成拦截器对象Interceptor,然后把这些拦截器封装为一个链对象,再把代理对象、目标对象、目标方法、目标方法参数和拦截器链对象封装到一个ReflectiveMethodInvocation类对象中然后调用了ReflectiveMethodInvocation类对象的proceed()方法,马上来看看这个方法的实现,其代码如下所示:

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    ...省略一些代码
    public Object proceed() throws Throwable {
        // We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        // 从拦截器链中获取当前索引位置处的拦截器
        Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                // 拦截器与当前目标方法匹配,则开始调用拦截器
                return dm.interceptor.invoke(this);
            }
            else {
                // 拦截器与当前目标方法不匹配,则调用下一个拦截器
                return proceed();
            }                            
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    @Nullable
    protected Object invokeJoinpoint() throws Throwable {
        // 调用目标方法
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
    ...省略一些代码
}

根据以上代码我们知道,procced()方法就是遍历所有拦截器依次调用拦截器对象的invoke()方法,所有拦截器遍历调用完了后再来调用目标方法。朋友们也许有个疑问,这个方法里面调用了拦截器对象的invoke()方法后,又是怎么回到这个procced()方法的呢?其实啊这个疑问我们就随便拿一个拦截器类的代码来看看就知道了,比如看看MethodBeforeAdviceInterceptor类的invoke()方法,其代码表示如下:

// 前置通知拦截器
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
    private final MethodBeforeAdvice advice;
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {

        // 调用织入的代码
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());

        // 又回到procced()方法
        return mi.proceed();
    }
}

// 后置返回通知拦截器
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
    private final AfterReturningAdvice advice;
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {

        // 先回到procced()方法
        Object retVal = mi.proceed();

        // 再调用织入的代码
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

到这里止,我们已经对JDK的动态代理拦截入口方法执行过程中的源代码进行了解读,接下来我们继续对CGLIb库动态生成代理拦截入口方法的执行过程中的源代码进行解读,我们知道通过CGLIb库动态代理创建代理对象后是通过添加了一个入口拦截器来做入口拦截的(如果不记得了请看上面红色字体的FixedChainStaticTargetInterceptor类这个位置),这个入口拦截器类为 FixedChainStaticTargetInterceptor,我们知道拦截器的入口方法为intercept()方法,那我们就来看看FixedChainStaticTargetInterceptor类的intercept()方法,其代码表示如下:

private static class FixedChainStaticTargetInterceptor implements MethodInterceptor, Serializable {
    ...省略一些代码
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 把代理对象、目标对象、目标方法、方法参数和拦截器链等对象封装到一个CglibMethodInvocation对象中,实际上CglibMethodInvocation类是ReflectiveMethodInvocation类的子类

        MethodInvocation invocation = new CglibMethodInvocation(
        proxy, this.target, method, args, this.targetClass, this.adviceChain, methodProxy);
        // If we get here, we need to create a MethodInvocation.
        // 开始调用拦截器

        Object retVal = invocation.proceed();
        retVal = processReturnType(proxy, this.target, method, retVal);
        return retVal;
    }
}

至此,对MethodInterceptor 方法拦截器链调用的整个过程的源代码就解读完毕了。

2.5 切面、切点、通知、连接点等源代码解读

Advisor 接口设计的代码表示如下:

// Advisor 就是一个切面,切面至少包含一个通知

public interface Advisor {

    /**
     * Common placeholder for an empty {@code Advice} to be returned from
     * {@link #getAdvice()} if no proper advice has been configured (yet).
     * @since 5.0
     */
    Advice EMPTY_ADVICE = new Advice() {};


    /**
     * Return the advice part of this aspect. An advice may be an
     * interceptor, a before advice, a throws advice, etc.
     * @return the advice that should apply if the pointcut matches
     * @see org.aopalliance.intercept.MethodInterceptor
     * @see BeforeAdvice
     * @see ThrowsAdvice
     * @see AfterReturningAdvice
     */

    // 切面的实现者必须包含一个通知
    Advice getAdvice();

    /**
     * Return whether this advice is associated with a particular instance
     * (for example, creating a mixin) or shared with all instances of
     * the advised class obtained from the same Spring bean factory.
     * <p><b>Note that this method is not currently used by the framework.</b>
     * Typical Advisor implementations always return {@code true}.
     * Use singleton/prototype bean definitions or appropriate programmatic
     * proxy creation to ensure that Advisors have the correct lifecycle model.
     * @return whether this advice is associated with a particular target instance
     */
    boolean isPerInstance();

}

Pointcut 接口设计的代码表示如下:

// Pointcut 就是一个切点,切点可以通过类过滤器和方法匹配器进行目标方法的匹配

public interface Pointcut {

    /**
     * Return the ClassFilter for this pointcut.
     * @return the ClassFilter (never {@code null})
     */

    // 切点的实现类必须包含一个类过滤器
    ClassFilter getClassFilter();

    /**
     * Return the MethodMatcher for this pointcut.
     * @return the MethodMatcher (never {@code null})
     */

    // 切点的实现类必须包含一个方法匹配器
    MethodMatcher getMethodMatcher();


    /**
     * Canonical Pointcut instance that always matches.
     */
    Pointcut TRUE = TruePointcut.INSTANCE;

}

Spring Aop 设计了一个包含切点的切面接口设计,其代码表示如下:

// 包含切点的切面接口,Advisor 接口设计中是包含了一个通知的,而这个接口中又包含了一个切点,所以这个接口最终既包含一个通知又包含一个切点,刚好与 @AspectJ注解声明在类上的切面就对上了

public interface PointcutAdvisor extends Advisor {

    /**
     * Get the Pointcut that drives this advisor.
     */

    // 切面的实现类必须包含一个切点
    Pointcut getPointcut();

}

Advice 接口设计的代码表示如下:

// 这个通知接口啥都没有,是一个标记接口

public interface Advice {

}

// 这个拦截器接口也是啥都没有,也是一个标记接口

public interface Interceptor extends Advice {

}

从以上两个接口的设计关系来看,我们可以认为拦截器也是一个通知

JoinPoint 接口设计的代码表示如下:

// 就是对目标对象的包装

public interface JoinPoint {
    String METHOD_EXECUTION = "method-execution";
    String METHOD_CALL = "method-call";
    String CONSTRUCTOR_EXECUTION = "constructor-execution";
    String CONSTRUCTOR_CALL = "constructor-call";
    String FIELD_GET = "field-get";
    String FIELD_SET = "field-set";
    String STATICINITIALIZATION = "staticinitialization";
    String PREINITIALIZATION = "preinitialization";
    String INITIALIZATION = "initialization";
    String EXCEPTION_HANDLER = "exception-handler";
    String SYNCHRONIZATION_LOCK = "lock";
    String SYNCHRONIZATION_UNLOCK = "unlock";
    String ADVICE_EXECUTION = "adviceexecution";

    String toString();

    String toShortString();

    String toLongString();

    Object getThis();

    Object getTarget();

    Object[] getArgs();

    Signature getSignature();

    SourceLocation getSourceLocation();

    String getKind();

    StaticPart getStaticPart();

    public interface EnclosingStaticPart extends StaticPart {
    }

    public interface StaticPart {
        Signature getSignature();

        SourceLocation getSourceLocation();

        String getKind();

        int getId();

        String toString();

        String toShortString();

        String toLongString();
    }
}

三、学习后的总结
3.1 Spring Aop 用代码的形式如何声明一个切面?

Spring Aop 是使用一个@AspectJ注解声明在一个类上面,Spring就认为这就是一个切面类,Spring在getBean()的过程当中就会解析这个类,比如具体代码表示如下:

@Aspect
@Component
public class OperateLogAspect {
    
    // 配置织入点
    @Pointcut("@annotation(com.**.interceptor.OperateLog)")
    public void logPointCut() {
    }

    /**
     * 处理请求前执行
     */
    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        执行代码块
    }

    /**
     * 处理完请求后执行
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        执行代码块
    }

    /**
     * 发生异常后执行
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        执行代码块
    }

}

注意:@AspectJ注解声明的类上一定要加上@Component注解,否则就会失效,原因是只有被Spring容器管理的Bean,Spring才会去解析每一个Bean的特点功能。

3.2 Spring Aop 声明的 @AspectJ 切面类是在什么时候解析成 Advisor 切面对象的?

是在getBean()的过程当中给bean进行初始化后置处理的扩展调用中切入的,是由一个实现了BeanPostProcessor接口的AbstractAutoProxyCreator类中的wrapIfNecessary()方法里在代理对象创建之前进行解析的,具体过程请看2.2这个章节的源代码解读。

3.3 Spring Aop  切面对象 Advisor 又是在什么时候适配成 MethodInterceptor 方法拦截器对象的?

是在代理对象第一次被拦截调用的时候,具体过程请看2.3这个章节的源代码解读。

3.4 Spring Aop 方法拦截器 MethodInterceptor 是在什么时候调用的?又是如何调用的?

具体请看2.4这个章节的源代码解读。

3.5 把以上问题搞清楚了后我们就来总结 Spring Aop 中所谓的切面、切点、通知、连接点都是些什么东西?用代码是怎么表示的,他们间的关系结构是什么样的?

切面:用 @AspectJ 注解声明在一个类上,就表示这个类是一个切面类,最终解析成一个或多个 Advisor 切面对象

切点:用 @PointCut 注解声明在一个方法上,就表示一个切点表达式,这个表达式可以是一个路径表达式,也可以是一个注解表达式,最终用 PointCut 表示一个切点对象

通知:用 @Advice 及其子注解(如:@Before)声明在一个方法上,就表示这个方法是一个通知方法,然后给注解指定切点表达式表示满足啥条件下应用此通知,最终用 BeforeAdvice等表示一个通知对象

连接点:就是需要应用切面的一个目标方法,目标方法通过切点表达式进行匹配后,如果匹配上了,就说明这个目标方法就是一个连接点,在这个连接点上可以应用相关通知,最终用 JoinPoint表示一个连接点对象

根据对切面(Advisor)、切点(Pointcut)、通知(Advice)、拦截器(Interceptor)、连接点(JoinPoin)这些概念的说明和这些概念对应接口设计的代码结构来看,我们可以把他们之间的关系总结为如下图所示:

  • 37
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值