Spring 4.3 源码分析之 Aop 组件概述

1. Spring Aop 概述

AOP(Aspect-Oriented Programming) 面向切面编程, 这种编程模型是在 OOP(Object-Oriented Programming) 的基础上诞生的一种编程模型, 我们可以简单的将其理解为: 在程序中具有公共特性的某些类/某些方法上进行拦截, 在方法执行的前面/后面/执行结果返回后 增加执行一些方法 (PS: 对, 就这么简单, 最起码 Spring 中是这样的); 在 Spring 中主要通过了CGLib|动态代理来实现 -> CGLib(通过实现一个子类来控制对原始类的方法调用) 与 Proxy(创建一个 Proxy 类, 内部通过反射来调用原始类) 来实现 <-- 这两个实现类都可以通过 HSDB 来获取! , 对于 aop 主要有以下组件

2. Spring Aop 组件 -> Pointcut

Pointcut: 这个类位于 "org.springframework.aop" 包中, 它的主要作用还是定义切面的匹配点, 在 Spring Aop 中匹配的点主要是 class 与 method 这两个方面, 分别为 ClassFilter 与 MethodFilter

// 由 ClassFilter 与 MethodMatcher 组成的 pointcut
public interface Pointcut {

    // 类过滤器, 可以知道哪些类需要拦截
    ClassFilter getClassFilter();

    // 方法匹配器, 可以知道哪些方法需要拦截
    MethodMatcher getMethodMatcher();

    // 匹配所有对象的 Pointcut
    Pointcut TRUE = TruePointcut.INSTANCE;
}

上面的接口中定义了 Pointcut 的主要方法, 从中我们可以看出, Pointcut 的匹配主要是根据 class 与 method 来进行匹配的; 在 Spring 中主要有以下几类:

1. NameMatchMethodPointcut:            通过正则表达式匹配方法名字的 Pointcut (PS: 其中 ClassFilter = ClassFilter.TRUE)
2. ControlFlowPointcut:                根据在当前线程的堆栈信息中的方法名来决定是否切入某个方法
3. ComposablePointcut:                 组合模式的 Pointcut, 主要分成两种: 1.组合中所有都匹配算成功  2. 组合中都不匹配才算成功
4. TransactionAttributeSourcePointcut: 通过 TransactionAttributeSource 在 类的方法上提取事务注解的属性 @Transactional 来判断是否匹配, 提取到则说明匹配, 提取不到则说明匹配不成功
5. AnnotationJCacheOperationSource:    通过 AnnotationJCacheOperationSource 在方法上提取注解 CacheResult, CachePut, CacheRemove, CacheRemoveAll 来判断是否匹配成功 (PS: 这与TransactionAttributeSourcePointcut相似 )
6. AspectJExpressionPointcut:           通过 AspectJ 包中的组件进行方法的匹配
7. JdkRegexpMethodPointcut:            通过 正则表达式来匹配方法

上述中的 TransactionAttributeSourcePointcut 其实就是Spring注解式事务的 Pointcut, 通过匹配方法上 @Transactional 标签来确定方法是否匹配; 而 AspectJExpressionPointcut 其实就是 AspectJ 包中的工具类来进行匹配

3. Spring Aop 组件 -> Advice

Advice: 建议忠告, 劝告, 通知, 这其实最开始是 aopalliance 包中的一个空接口, 接口的存在主要是为了标示对应类为 Advice; 而在Spring Aop 中 Advice 其实表示的是在 Pointcut 点上应该执行的方法, 而这个方法可以在 Pointcut 的前面/后面/包裹 Pointcut/Pointcut抛出异常时/整个 Pointcut 执行成功返回时执行 <- 有时语言不能完全解释代码所想表达的意思, 那我们直接来看代码吧!
Advice: 其主要分成两类: 普通advice 与
Interceptor/MethodInterceptor, 通常Spring是将被 AspectJ 标注的方法解析成各种 Advice(BeforeAdvice, AfterAdvice, ThrowingAdvice, AfterReturingAdvice 或 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice)

1. Advice: 
      1.1 MethodBeforeAdvice:       在切面方法之前前执行的方法, 主要有以下类别
          CountingBeforeAdvice:     它是MethodCounter的子类, 在MethodCounter中通过 Map 来统计方法执行的次数, 是其最简单的一个实现;
          AspectJMethodBeoreAdvice:这是通过解析被 org.aspectj.lang.annotation.Before 注解注释的方法时解析成的Advice
      1.2 AfterReturningAdvice:         在切面方法执行后(这里的执行后指不向外抛异常, 否则的话就应该是 AspectJAfterThrowingAdvice 这种 Advice); 主要有以下几种类型
          CountingAfterReturningAdvice: 是最简单的 ReturningAdvice(PS: CountingAfterReturningAdvice 是MethodCounter的子类, 在MethodCounter中通过 Map 来统计方法执行的次数)
          AspectJAfterAdvice:           解析 AspectJ 中的 After 属性来生成的 Advice(PS: 在java中的实现其实就是在 finally 方法中调用以下对应要执行的方法)
          AspectJAfterReturningAdvice:  解析 AspectJ 中的 AfterReturning 属性来生成的 Advice(PS: 若切面方法抛出异常, 则这里的方法就将不执行)
          AspectJAfterThrowingAdvice:   解析 AspectJ 中的 AfterThrowing 属性来生成的 Advice(PS: 若切面方法抛出异常, 则这里的方法就执行)
      1.3 AspectJAroundAdvice:          将执行类 MethodInvocation(MethodInvocation其实就是Pointcut) 进行包裹起来, 并控制其执行的 Advice (其中 Jdk中中 Proxy 使用 ReflectiveMethodInvocation, 而 Cglib 则使用 CglibMethodInvocation)
          (PS: 注意上面只是 Advice, 而在 JdkDynamicProxy中执行的是 MethodInterceptor, 对于这层接口的适配则都是交给 AdvisorAdapter -> 将 advice 适配成 MethodInterceptor)

2. MethodInterceptor:  
      2.1 ExposeInvocationInterceptor:      将当前 MethodInvocation 放到当前线程对应的 ThreadLoadMap 里面的, 这是一个默认的 Interceptor, 在 AspectJAwareAdvisorAutoProxy获取何时的 Advisor 时会调用自己的 extendAdvisors 方法, 从而将 ExposeInvocationInterceptor 方法执行链表的第一位
      2.2 SimpleTraceInterceptor:           将 MethodInvocation 的信息写入 日志的 MethodInterceptor
      2.3 AfterReturningAdviceInterceptor:  这个类其实就是将 AfterReturningAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 AfterReturningAdviceAdapter
      2.4 MethodBeforeAdviceInterceptor:    这个类其实就是将 MethodBeforeAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 MethodBeforeAdviceAdapter
      2.5 NopInterceptor:                   非常简单的 MethodInterceptor, 其进行方法调用的统计技术这样的工作
      2.6 ThrowsAdviceInterceptor:          这个类其实就是将 ThrowsAdvice 包裹成 MethodInterceptor 的适配类, 而做对应适配工作的就是 ThrowsAdviceAdapter
      2.7 TransactionInterceptor:           这个类就是大名鼎鼎的注解式事务的工具类, 这个类通过获取注解在方法上的 @Transactional 注解的信息来决定是否开启事务的 MethodInterceptor (PS: 在注解式事务编程中将详细叙述)

上面的 Advice 类别概述, 而又有以下说明:

1. 无论通过aop命名空间/AspectJ注解注释的方法, 其最终都将解析成对应的 Advice
2. 所有解析的 Advice 最终都将适配成 MethodInterceptor, 并在 JdkDynamicAopProxy/CglibAopProxy中进行统一调用
4. Spring Aop 组件 -> Advisor

Advisor 其实它就是 Pointcut 与 Advice 的组合, Advice 是执行的方法, 而要知道方法何时执行, 则 Advice 必需与 Pointcut 组合在一起, 这就诞生了 Advisor 这个类(PS: 你可以尝试这样理解 -> Advice表示建议,
Pointcut表示建议的地点, Advisor表示建议者, 建议的者拥有建议的功能, 并且知道在哪儿建议 <- 纯属于歪歪), 主要有以下几个类:

1. PointcutAdvisor:          我们在 Spring 中常用的 Advisor, 包含一个 Pointcut 与一个 advice
2. AspectJPointcutAdvisor:   这个是 Spring 解析 aop 命名空间时生成的 Advisor(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice, Pointcut 则是AspectJExpressionPointcut), 对于这个类的解析是在 ConfigBeanDefinitionParser
3. InstantiationModelAwarePointcutAdvisorImpl: 这个Advisor是在Spring解析被 @AspectJ注解注释的类时生成的 Advisor, 而这个 Advisor中的 Pointcut与Advice都是由 ReflectiveAspectJAdvisorFactory 来解析生成的(与之对应的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice, Pointcut 则是AspectJExpressionPointcut), 解析的步骤是: AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors() -> BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors() -> ReflectiveAspectJAdvisorFactory.getAdvisors() -> ReflectiveAspectJAdvisorFactory.getAdvisor() 最终生成了 InstantiationModelAwarePointcutAdvisorImpl (当然包括里面的 Pointcut 与 advice 也都是由 ReflectiveAspectJAdvisorFactory 解析生成的)
4. TransactionAttributeSourceAdvisor: 一个基于 MethodInterceptor(其实是 TransactionInterceptor)与 TransactionAttributeSourcePointcut 的Advisor, 而这个类最常与 TransactionProxyFactoryBean使用
5. DefaultPointcutAdvisor:           最常用的 Advisor, 在使用编程式aop时, 很多时候会将 Advice / MethodInterceptor 转换成 DefaultPointcutAdvisor
6. NameMatchMethodPointcutAdvisor:    这个是在使用 NameMatchPointcutAdvisor时创建的 Advisor, 主要是通过 方法名来匹配是否执行 Advice
7. RegexpMethodPointcutAdvisor:       基于正则表达式来匹配 Pointcut 的 Advisor, 其中的 Pointcut 默认是 JdkRegexpMethodPointcut
8. DefaultBeanFactoryPointcutAdvisor: Spring 中解析 <aop:advisor> 时生成的 Advisor, 见 ConfigBeanDefinitionParser.parseAdvisor 
9. BeanFactoryTransactionAttributeSourceAdvisor: 在注解式事务编程时, 主要是由 BeanFactoryTransactionAttributeSourceAdvisor, AnnotationTransactionAttributeSource, TransactionInterceptor 组合起来进行事务的操作(PS: AnnotationTransactionAttributeSource 主要是解析方法上的 @Transactional注解, TransactionInterceptor 是个 MethodInterceptor, 是正真操作事务的地方, 而BeanFactoryTransactionAttributeSourceAdvisor 其实起着组合它们的作用); <- 与之相似的还有 BeanFactoryCacheOperationSourceAdvisor
5. Spring Aop 组件 -> Advised

Advised: 已经被建议的对象, 其中蕴含了:

// 这个 Advised 接口的实现着主要是代理生成的对象与AdvisedSupport (Advised的支持器)
public interface Advised extends TargetClassAware {

     // 这个 frozen 决定是否 AdvisedSupport 里面配置的信息是否改变
    boolean isFrozen();

     // 是否代理指定的类, 而不是一些 Interface
    boolean isProxyTargetClass();

     // 返回代理的接口
    Class<?>[] getProxiedInterfaces();

    // 判断这个接口是否是被代理的接口
    boolean isInterfaceProxied(Class<?> intf);

    // 设置代理的目标对象
    void setTargetSource(TargetSource targetSource);

    // 获取代理的对象
    TargetSource getTargetSource();

    // 判断是否需要将 代理的对象暴露到 ThreadLocal中, 而获取对应的代理对象则通过 AopContext 获取
    void setExposeProxy(boolean exposeProxy);

    // 返回是否应该暴露 代理对象
    boolean isExposeProxy();

     // 设置 Advisor 是否已经在前面过滤过是否匹配 Pointcut (极少用到)
    void setPreFiltered(boolean preFiltered);

    // 获取 Advisor 是否已经在前面过滤过是否匹配 Pointcut (极少用到)

    boolean isPreFiltered();

    // 获取所有的 Advisor
    Advisor[] getAdvisors();

    // 增加 Advisor 到链表的最后
    void addAdvisor(Advisor advisor) throws AopConfigException;

    // 在指定位置增加 Advisor
    void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

    // 删除指定的 Advisor
    boolean removeAdvisor(Advisor advisor);

    // 删除指定位置的 Advisor
    void removeAdvisor(int index) throws AopConfigException;

    // 返回 Advisor 所在位置de index
    int indexOf(Advisor advisor);

    // 将指定的两个 Advisor 进行替换
    boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

     // 增加 Advice <- 这个Advice将会包裹成 DefaultPointcutAdvisor
    void addAdvice(Advice advice) throws AopConfigException;

    // 在指定 index 增加 Advice <- 这个Advice将会包裹成 DefaultPointcutAdvisor
    void addAdvice(int pos, Advice advice) throws AopConfigException;

    // 删除给定的 Advice
    boolean removeAdvice(Advice advice);

    // 获取 Advice 的索引位置
    int indexOf(Advice advice);

    // 将 ProxyConfig 通过 String 形式返回
    String toProxyConfigString();
}

其实它主要完成的是以下几点:

1. Proxy代理的Interface
2. 代理的对象 TargetSource
3. 包裹这个 Advised 的Advisor, 以及对它的增删
4. 对 Advice 的增删

而其主要的实现者是:

1. AdvisedSupport:      这个类内部是 List<Advisor>, Advisor[], interfaces, DefaultAdvisorChainFactory(判断 Advisor 是否适合当前的方法), targetSource
2. ProxyCreatorSupport: 这个类继承 AdvisedSupport, 但是在这个类中主要还是通过 AopProxyFactory 来完成代理对象的创建, 见 ProxyCreatorSupport.createAopProxy()
3. ProxyFactory:        这个类通过构造函数中的 proxyInterface/interceptor/targetSource 来创建代理对象(这个类是编程式 AOP 中最常用的对象)
4. ProxyFactoryBean:    这个类是基于 FactoryBean 的 Proxy创建形式, 其通过代理的 Interface, targetSource 与指定的 interceptorNames 来创建对应的AopProxy, 最后生成对应的代理对象
5. AspectJProxyFactory: 将一个被 @AspectJ 注解标示的类丢入其中, 变创建了对应的代理对象 (这个类现在已经很少用了, 关于如何使用, 可以看这里(http://elim.iteye.com/blog/2397922))
6. Spring Aop 组件 -> TargetSource

TargetSource: 这个类的概念其实是动态代理作用的对象, 在 Spring 中又可以分为:

1. HotSwappableTargetSource:    进行线程安全的热切换到对另外一个对象实施动态代理操作
2. AbstractPoolingTargetSource: 每次进行生成动态代理对象时都返回一个新的对象
3. ThreadLocalTargetSource:     为每个进行请求的线程维护一个对象的 TargetSource
4. SingletonTargetSource:       最普遍最基本的单例 TargetSource, 在 Spring 中生成动态代理对象, 一般都是用这个 TargetSource
7. Spring Aop 组件 -> AdvisorChainFactory

AdvisorChainFactory: 这个接口主要定义了从 Advised中获取 Advisor 并判断其是否与 对应的 Method 相匹配, 最终返回的是MethodInterceptor; 其中对 Advisor 转化成 MethodInterceptor 的工作都是交由 DefaultAdvisorAdapterRegistry 来完成, 下面就是其主逻辑:

// 获取匹配 targetClass 与 method 的所有切面的通知
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, Class<?> targetClass) {

    // This is somewhat tricky... We have to process introductions first,
    // but we need to preserve order in the ultimate list.
    List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);                                  // PS: 这里 config.getAdvisors 获取的是 advisors 是数组
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);                                       // 判断是有 IntroductionAdvisor 匹配到
    // 下面这个适配器将通知 [Advice] 包装成拦截器 [MethodInterceptor]; 而 DefaultAdvisorAdapterRegistry则是适配器的默认实现
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    for (Advisor advisor : config.getAdvisors()) {              // 获取所有的 Advisor
        if (advisor instanceof PointcutAdvisor) {               // advisor 是 PointcutAdvisor 的子类
            // Add it conditionally.
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                                                                // 判断此切面 [advisor] 是否匹配 targetClass (PS: 这里是类级别的匹配)
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                /** 通过对适配器将通知 [Advice] 包装成 MethodInterceptor, 这里为什么是个数组? 因为一个通知类
                 *  可能同时实现了前置通知[MethodBeforeAdvice], 后置通知[AfterReturingAdvice], 异常通知接口[ThrowsAdvice]
                 *   环绕通知 [MethodInterceptor], 这里会将每个通知统一包装成 MethodInterceptor
                 */
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                                                                // 是否匹配 targetClass 类的 method 方法     (PS: 这里是方法级别的匹配)
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    if (mm.isRuntime()) {                       // 看了对应的所有实现类, 只有 ControlFlowPointcut 与 AspectJExpressionPointcut 有可能 返回 true
                        // Creating a new object instance in the getInterceptors() method
                        // isn't a problem as we normally cache created chains.
                        // 如果需要在运行时动态拦截方法的执行则创建一个简单的对象封装相关的数据, 它将延时
                        // 到方法执行的时候验证要不要执行此通知
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));           // 里面装的是 Advise 与 MethodMatcher
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        else if (advisor instanceof IntroductionAdvisor) {  // 这里是 IntroductionAdvisor
            // 如果是引入切面的话则判断它是否适用于目标类, Spring 中默认的引入切面实现是 DefaultIntroductionAdvisor 类
            // 默认的引入通知是 DelegatingIntroductionInterceptor 它实现了 MethodInterceptor 接口s
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }
    return interceptorList;
}
8. Spring Aop 组件 -> DefaultAdvisorAdapterRegistry

DefaultAdvisorAdapterRegistry: 这里类里面存在着 MethodBeforeAdviceAdapter, AfterReturningAdviceAdapter, ThrowsAdviceAdapter <- 这三个类是将 Advice适配成MethodInterceptor 的适配类; 而其本身具有两个重要的功能:

1. 将 Advice/MethodInterceptor 包裹成 DefaultPointcutAdvisor
2. 通过上面的三个适配类将 Advisor 中的 Advice 适配成对应的MethodInterceptor
   (PS: 在代理对象执行时, 执行的都是MethodInterceptor, 当然在进行配置时既可以配置 Advice, MethodInterceptor, Advisor)
9. Spring Aop 组件 -> AopProxyFactory

AopProxyFactory: 这个接口中定义了根据 AdvisedSupport 中配置的信息来生成合适的AopProxy (主要分为 基于Java 动态代理的 JdkDynamicAopProxy 与基于 Cglib 的ObjenesisCglibAopProxy), 主逻辑如下:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 启用了 优化配置(原因就是 cglib 的性能比 JDK Proxy 要好) || 启用了直接代理目标类模式 || 没有指定要代理的接口(除了 接口SpringProxy)
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        // 代理的对象是否是接口 或 targetClass 是否是 java.lang.reflect.Proxy 的子类
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {  
            return new JdkDynamicAopProxy(config);
        }
        // 创建 cglib 代理的工厂对象
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        // 返回创建 JDK 代理的工厂对象
        return new JdkDynamicAopProxy(config);
    }
}
PS: 这里补充个知识点 Cglib 生成代理类的速度比 Proxy 生成的慢(几乎到10倍数), 但其执行速度是 Proxy 的 10倍 (可能基于不同版本的 jar 包测出的数据会稍有不同)

而在我们日常使用中 JdkDynamicAopProxy 是最常使用的, 下面直接看一下其执行的主逻辑

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    Object oldProxy = null;
    boolean setProxyContext = false;
    // 目标对象的包装类, 通过 AdvisedSupport的setTarget方法设置的会自动封闭成 TargetSource 的实现 SingletonTargetSource
    TargetSource targetSource = this.advised.targetSource;
    Class<?> targetClass = null;
    Object target = null;

    try {
        // 被代理的接口中没有定义 equals 方法且目前方法是 equals 方法, 则调用 equals 方法比较两代对象所代理的接口
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            // 如果目标对象没有实现 object 类的基础方法 euqals
            return equals(args[0]);
        }
        // hashCode 方法的处理
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            // 如果目标对象没有实现 object 类的基础方法 hashCode
            return hashCode();
        }
        // 如果调用的方法是 DecoratingProxy声明的
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        /**
         * Class类的 isAssignableFrom(Class cls) 方法:
         * 自身类.class.isAssignableFrom(自身类或子类.class) 返回 true
         *
         * 对 Advised 接口或者子接口中的方法的调用不经过任何拦截器, 直接委托给Advised 对象中的方法
         * (此 if 块 的目的是实现将 advised 对象引入代理对象), this.advised.opaque 默认情况下是 false(它只是一个开关
         * 选项, 控制代理对象是否可以操作 advised)
         */
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // Service invocations on ProxyConfig with the proxy config...
            // 调用 advised 的method 方法
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;
        // 当目标对象内部的自我调用无法实施切面中的增强则需要增强则需要通过此属性暴露代理
        if (this.advised.exposeProxy) {
            // 把当前代理对象放到 AopContext 中(其内部使用 ThreadLocal 存着), 并返回上下文中原来的代理对象, 并且保留之前暴露设置的代理
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // May be null. Get as late as possible to minimize the time we "own" the target,
        // in case it comes from a pool.
        // 得到目标对象
        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }

        // 获取当前方法的拦截器链
        // Get the interception chain for this method.
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        // 检测是否含有 MethodInterceptor
        if (chain.isEmpty()) {
            // 没有任何拦截器需要执行则直接执行目标对象方法
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            /**
             * 如果有拦截器的设定, 那么需要调用拦截器之后才调用目标对象的相应方法
             * 通过 构造一个 ReflectiveMethodInvocation 来实现, 下面会看
             * 这个 ReflectiveMethodInvocation 类的具体实现
             */
            // We need to create a method invocation...
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            // 执行拦截器链
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        Class<?> returnType = method.getReturnType();
        // 处理返回目标对象本身的情况, 也许某些方法是返回this引用, 此时需要返回代理对象而不是目标对象
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {           // 从这里我们可以发现, 拦截器的返回值若设定的不是 null, 但是 你主动设置为 null, 则将会报出异常
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            // 如果此 targetSource 不是一个静态的 targetSource, 那么释放此 target, 默认的 SingletonTargetSource.isStatic 方法是 true 的
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            // 还原之前的代理对象
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
10. Spring Aop 组件 -> Joinpoint的子类 MethodInvocation

MethodInvocation 是进行 invoke 对应方法/MethodInterceptor的类, 其主要分成用于 Proxy 的 ReflectiveMethodInvocation, 与用于 Cglib 的 CglibMethodInvocation; ReflectiveMethodInvocation 其实就是就是递归的调用 MethodInterceptor, 当没有 MethodInterceptor可以调用时, 则执行对应的切面点的方法, 如下:

/**
 * 实现前置增强在目标方法前调用, 后置增强在目标方法后调用
 */
@Override
public Object proceed() throws Throwable {
    // 执行完所有增强执行切点方法
    // currentInterceptorIndex 默认等于 -1 的, 它记录着当前执行到了哪个拦截器
    // interceptorsAndDynamicMethodMatchers 代表着匹配了的 MethodInterceptor
    //  We start with an index of -1 and increment early.
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 如果所有的 拦截器都执行完了的话, 则调用 invokeJoinPoint 方法去执行目标对象的目标方法 (反射)
        return invokeJoinpoint();
    }
    
    // 得到当前要执行的拦截器(拦截器是顺序执行的 )
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // 下面判断当前拦截器是不是一个动态拦截器
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { //  其实在 Spring 中 主要的实现类是 AspectJExpressionPointcut
        // 动态 匹配 方法 拦截
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        // 这里调用 MethodMatcher 类中带3个参数的 matches 方法
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            // 匹配目标类的目标方法后执行拦截器
            return dm.interceptor.invoke(this);
        }
        else {
            // 递归调用, 下一个拦截器或目标类的方法
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            return proceed();
        }
    }
    else {
        // 将 this作为参数(MehtodInvocation)传递以保证当前实例中调用链的执行
        // 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);
    }
}
11. Spring Aop 组件 -> AbstractAutoProxyCreator

AbstractAutoProxyCreator: 这个类是声明式 Aop 编程中非常重要的一个角色, 我们可以从以下几点来解析它:

1. AbstractAutoProxyCreator继承了 ProxyProcessorSupport, 所以它具有了ProxyConfig中动态代理应该具有的配置属性
2. AbstractAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor(包括实例化的前后置函数, 初始化的前后置函数) 并进行了实现
3. 实现了 创建代理类的主方法 createProxy 方法
4. 定义了抽象方法 getAdvicesAndAdvisorsForBean(获取 Bean对应的 Advisor)

AbstractAutoProxyCreator 中等于是构建了创建 Aop 对象的主逻辑, 而其子类 AbstractAdvisorAutoProxyCreator 实现了getAdvicesAndAdvisorsForBean 方法, 并且通过工具类 BeanFactoryAdvisorRetrievalHelper(PS: 它的方法findAdvisorBeans中实现类获取容器中所有 Advisor 的方法) 来获取其对应的 Advisor;
AbstractAutoProxyCreator 的子类中主要有以下几个:

1. AspectJAwareAdvisorAutoProxyCreator: 通过解析 aop 命名空间的配置信息时生成的 AdvisorAutoProxyCreator, 主要通过ConfigBeanDefinitionParser.parse() -> ConfigBeanDefinitionParser.configureAutoProxyCreator() -> AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary() -> AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(); 与之对应的 Pointcut 是AspectJExpressionPointcut, Advisor 是 AspectJPointcutAdvisor, Advice 则是 AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice
2. AnnotationAwareAspectJAutoProxyCreator: 这是基于 @AspectJ注解生成的 切面类的一个 AbstractAutoProxyCreator, 解析额工作交给了 AspectJAutoProxyBeanDefinitionParser, 步骤如下AspectJAutoProxyBeanDefinitionParser.parse() -> AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary() -> AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary()
3. DefaultAdvisorAutoProxyCreator: 这个类也是 AbstractAutoProxyCreator的子类, 它帅选作用的类时主要是根据其中的 advisorBeanNamePrefix(类名前缀)配置进行判断
4. BeanNameAutoProxyCreator: 通过类的名字来判断是否作用(正则匹配)

上面这几个类主要是声明式 Aop 编程的主要功能类, 会在后续的篇章中详细概述!

12. 总结

本篇主要介绍了 Spring-Aop 中的主要构建, 并进行相应的说明, 单纯的讲 aop 这个概念其实不复杂, 而在 Spring 中, 主要表现在如下几点:

1. 涉及的组件多 ->  Pointcut, Advice, MethodInterceptor, Advised, Advisor, TargetSource, AopProxyFactory, MethodInvocation, AbstractAutoProxyCreator, 这也造成掌握 Spring-aop 的难度
2. 实现aop需要多个基础功能的支持(AspectJ中的注解及注解解析, Cglib, java中的 Proxy, Asm字节码(主要式解析方法中的参数名))
3. 结合了 BeanPostProcessor 在Bean的实例化/初始化阶段就进行生成对应的代理类(比如 AspectJAwareAdvisorAutoProxyCreator与AnnotationAwareAspectJAutoProxyCreator)
13. 参考资料

Spring技术内幕分析
Spring IOC 原理
Spring 5 源码分析
开涛的 Spring杂谈
伤神的 Spring源码分析
Spring Core
Spring IOC 源码分析
Spring源码情操陶冶
Spring 揭秘 (PS: 这本书绝对给力)
Spring 技术内幕
Spring 源码深度分析
Spring 高级程序设计 (PS:这本书已经绝版, 所以当时是自己下载 pdf, 然后联系淘宝卖家忙帮复印, 其实就是英文版本的 "Pro Spring 3")
深入分析 Java Web(PS: 许令波写的, 虽然是本老书, 但是里面分析得确实很深入)
expert one-on-one J2EE Development without EJB (PS: Spring 作者自己写的书, 当时也是下载 PDF, 联系淘宝卖家复印购买到的)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容

  • 本博中关于spring的文章:Spring IOC和AOP原理,Spring事务原理探究,Spring配置文件属性...
    Maggie编程去阅读 4,098评论 0 34
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,628评论 18 139
  • title: Spring_AOP源码分析date: 2016-11-03 01:15:11categories:...
    raincoffee阅读 1,735评论 2 36
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,445评论 1 133
  • 作者:何少波 你我挥别过往,过往成为历史,再回首。 飘雪季,这一年,点滴过...... 这是最棒的一年,站在贺兰山...
    南塬牛阅读 400评论 0 3