SpringAOP源码解析

来源:互联网 发布:vs for mac 离线 编辑:程序博客网 时间:2024/05/31 11:03

一、SpringAOP的概述 
1、AOP概念 
AOP是Aspect-Oriented Programming(面向切面编程)的简称。维基百科的解释如下: 
Aspect是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。从关注点中分离出横切关注点是面向切面的程序设计的核心。分离关注点使解决特定领域问题的代码从业务逻辑代码中独立出来,业务逻辑的代码中不再含有针对特定领用问题代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好的管理起来。 
2、Advice通知 
Advice定义在连接点为切面增强提供织入接口。在Spring AOP中,他主要描述Spring AOP围绕方法调用而注入的切面行为。Advice是定义在org.aopalliance.aop.Advice中的接口。在Spring AOP使用这个统一接口,并通过这个接口为AOP切面增强的织入功能做了更多的细节和扩展,比如提供了更具体的通知类型,如BeforeAdvice,AfterAdvice,ThrowsAdvice等。 
2.1 BeforeAdvice 
首先我们从BeforeAdvice开始: 
在BeforeAdvice的继承关系中,定义了为待增强的目标方法设置的前置增强接口MethodBeforeAdvice,使用这个前置接口需要实现一个回调函数:

void before(Method method,Object[] args,Object target) throws Throwable;
  • 1

作为回调函数,before方法的实现在Advice中被配置到目标方法后,会在调用目标方法时被回调。具体的参数有:Method对象,这个参数是目标方法的反射对象;Object[]对象数组,这个对象数组中包含目标方法的输入参数。以CountingBeforeAdvice为例来说明BeforeAdvice的具体使用,CountBeforeAdvice是接口MethodBeforeAdvice的具体实现,他只是统计被调用方法的次数,作为切面增强实现,他会根据调用方法的方法名进行统计,把统计结果根据方法名和调用次数作为键值对放入一个map中。代码如下:

public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice {    //实现方法前置通知MethodBeforeAdvice接口的方法    public void before(Method m, Object[] args, Object target) throws Throwable {    //以目标对象方法作为参数,调用父类MethodCounter的count方法统计方法调用次数        count(m);    }}CountingBeforeAdvice的父类MethodCounter的源码如下:public class MethodCounter implements Serializable {    //方法名—>方法调用次数的map集合,存储方法的调用次数    private HashMap<String, Integer> map = new HashMap<String, Integer>();    //所有方法的总调用次数    private int allCount;    //统计方法调用次数,CountingBeforeAdvice的调用入口    protected void count(Method m) {        count(m.getName());    }    //统计指定名称方法的调用次数    protected void count(String methodName) {        //从方法名—>方法调用次数集合中获取指定名称方法的调用次数        Integer i = map.get(methodName);//如果调用次数不为null,则将调用次数加1,如果调用次数为null,则设置调用次数为1        i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1);        //重新设置集合中保存的方法调用次数        map.put(methodName, i);        //所有方法总调用次数加1        ++allCount;    }    //获取指定名称方法的调用次数    public int getCalls(String methodName) {        Integer i = map.get(methodName);        return (i != null ? i.intValue() : 0);    }    //获取所有方法的总调用次数    public int getCalls() {        return allCount;    }    public boolean equals(Object other) {        return (other != null && other.getClass() == this.getClass());    }    public int hashCode() {        return getClass().hashCode();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

2.2 AfterAdvice 
在Advice的实现体系中,Spring还提供了AfterAdvice这种通知类型,这里以AfterReturningAdvice通知的实现为例,代码如下:

public interface AfterReturningAdvice extends AfterAdvice {//后置通知的回调方法,在目标方法对象调用结束并成功返回之后调用// returnValue参数为目标方法对象的返回值,method参数为目标方法对象,args为    //目标方法对象的输入参数    void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

afterReturning方法也是一个回调函数,AOP应用需要在这个接口实现中提供切面增强的具体设计,在这个Advice通知被正确配置以后,在目标方法调用结束并成功返回的时候,接口会被SpringAOP调用。与前面分析的一样,在Spring AOP包中,同样可以看到CountingAfterReturningAdvice,实现基本一致:

public class CountingAfterReturningAdvice extends MethodCounter implements AfterReturningAdvice {    //实现后置通知AfterReturningAdvice的回调方法    public void afterReturning(Object o, Method m, Object[] args, Object target) throws Throwable {        //调用父类MethodCounter的count方法,统计方法的调用次数        count(m);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在实现AfterReturningAdvice的接口方法afterReturning中,可以调用MethodCounter的count方法,从而完成根据方法名对目标方法调用次数的统计。 
2.3 ThrowsAdvice 
下面我们来看一下Advice通知的另一种类型ThrowsAdvice。对于ThrowsAdvice,并没有制定需要实现的接口方法,他在抛出异常时被回调,这个回调是AOP使用反射机制来完成的。可以通过CountingThrowsAdvice来了解ThrowsAdvice的使用方法:

public static class CountingThrowsAdvice extends MethodCounter implements ThrowsAdvice {        //当抛出IO类型的异常时的回调方法,统计异常被调用的次数        public void afterThrowing(IOException ex) throws Throwable {            count(IOException.class.getName());        }        //当抛出UncheckedException类型异常时的回调方法,统计异常被调用的次数        public void afterThrowing(UncheckedException ex) throws Throwable {            count(UncheckedException.class.getName());        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

3、Pointcut切点 
决定Advice通知应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法的集合,这些集合的选取可以按照一定的规则来完成。Pointcut通常意味着标识方法,例如,这些需要增强的地方可以由某个正则表达式进行标识,或根据某个方法名进行匹配。源码如下:

public interface Pointcut {    //获取类过滤器    ClassFilter getClassFilter();    //获取匹配切入点的方法        MethodMatcher getMethodMatcher();    //总匹配的标准切入点实例    Pointcut TRUE = TruePointcut.INSTANCE;} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

查看Pointcut切入点的继承体系,发现Pointcut切入点的实现类非常的多,如针对注解配置的AnnotationMatchingPointcut、针对正则表达式的JdkRegexpMethodPointcut等等,我们以JdkRegexpMethodPointcut为例,分析切入点匹配的具体实现,源码如下:

public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {    //要编译的正则表达式模式    private Pattern[] compiledPatterns = new Pattern[0];    //编译时要排除的正则表达式模式    private Pattern[] compiledExclusionPatterns = new Pattern[0];    //将给定的模式字符串数组初始化为编译的正则表达式模式    protected void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {        this.compiledPatterns = compilePatterns(patterns);    }    //将给定的模式字符串数组初始化为编译时要排除的正则表达式模式    protected void initExcludedPatternRepresentation(String[] excludedPatterns) throws PatternSyntaxException {        this.compiledExclusionPatterns = compilePatterns(excludedPatterns);    }    //使用正则表达式匹配给定的名称    protected boolean matches(String pattern, int patternIndex) {        Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);        return matcher.matches();    }    //使用要排除的正则表达式匹配给定的名称    protected boolean matchesExclusion(String candidate, int patternIndex) {        Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate);        return matcher.matches();    }    //将给定的字符串数组编译为正则表达的模式    private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {        Pattern[] destination = new Pattern[source.length];        for (int i = 0; i < source.length; i++) {            destination[i] = Pattern.compile(source[i]);        }        return destination;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

4、Advisor通知器 
完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把他们结合起来,完成这个作用的就是Advisor。通过他可以定义应该使用哪个通知并在哪个关注点使用它。在DefaultPointcutAdvisor中有两个属性,分别是advice和Pointcut。通过这两个属性,可以分别配置Advice和Pointcut。源码如下:

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {    //默认切入点    //Pointcut.TRUE在切入点中的定义为:Pointcut TRUE = TruePointcut.INSTANCE;    private Pointcut pointcut = Pointcut.TRUE;    //无参构造方法,创建一个空的通知器    public DefaultPointcutAdvisor() {    }    //创建一个匹配所有方法的通知器    public DefaultPointcutAdvisor(Advice advice) {        this(Pointcut.TRUE, advice);    }    //创建一个指定切入点和通知的通知器    public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {        this.pointcut = pointcut;        setAdvice(advice);    }    //为通知设置切入点    public void setPointcut(Pointcut pointcut) {        this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);    }    //获取切入点    public Pointcut getPointcut() {        return this.pointcut;    }    public String toString() {        return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

上述源码中,通知器的默认切入点是Pointcut.TRUE,Pointcut.TRUE在切入点中的定义为:Pointcut TRUE = TruePointcut.INSTANCE 
TruePointcut的INSTANCE是一个单件,比如使用static类变量来持有单件实例,使用private私有构造函数来确保除了在当前单件实现中,单件不会被再次创建和实例化。 


二、AOP的设计与实现 
1、JVM的动态代理特性** 
在Spring AOP实现中, 使用的核心技术时动态代理,而这种动态代理实际上是JDK的一个特性。通过JDK的动态代理特性,可以为任意Java对象创建代理对象,对于具体使用来说,这个特性使通过Java Reflection API来完成的。在此之前先简要复习一下Proxy模式,其静态类图如下: 
这里写图片描述 
我们可以看到有一个RealSubject,这个对象是目标对象,而在代理模式的设计中,会设计一个接口和目标对象一致的代理对象Proxy,它们都实现了接口Subject的request方法。在这种情况下,对目标对象的request调用,往往就被代理对象“浑水摸鱼”给拦截了。通过这种拦截,为目标对象的方法操作做了铺垫。 
在Proxy的调用过程中,如果客户调用Proxy的request方法,会在调用目标对象的request方法,会在调用目标对象的request方法的前后调用一系列的处理,而这一系列的处理相当于对目标对象来说是透明的,目标对象对这些处理可以毫不知情,这就是proxy模式。 
我们知道JDK中已经实现了这个Proxy模式,在基于Java虚拟机设计应用程序时,只需要直接使用这个特性就可以了。具体来说,可以再Java的Reflection包中看到proxy对象,这个对象生成后,所起的作用就类似于Proxy模式中的Proxy对象。在使用时,还需要为代理对象设计一个回调方法,这个回调方法起到的作用是,在其中假如了作为代理需要额外处理的动作。这个回调方法,如果在JDK中实现,需要实现下面所示的InvocationHandler接口:

public interface InvocationHandler{  public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;}
  • 1
  • 2
  • 3

至于invoke方法和Proxy挂上钩,熟悉proxy用法的读者都知道,只要在实现通过调用Proxy.newInstance方法生成具体的Proxy对象时,把InvocationHandler设置到参数里面就可以了,剩下的由Java虚拟机来完成。 
2、Spring AOP的设计分析 
Spring AOP以动态代理技术为基础,设计出了一系列AOP的横切实现,比如前置通知、返回通知、异常通知等。同时SpringAOP还提供了一系列的Pointcut来匹配切入点,可以使用现有的切入点来设计横切面,也可以扩展相关的Pointcut方法来切入需求。 
在Spring AOP中,虽然对于AOP的使用者来说,只需要配置相关的Bean定义即可,但仔细分析Spring AOP内部设计可以看到,为了让AOP起作用,需要完成一系列过程,比如,需要为目标对象建立代理对象,这个代理对象可以通过使用JDK的Proxy来完成,也可以通过第三方的类生成器CGLIB来完成。然后,还需要启动代理对象的拦截器来完成各种横切面的织入,这一系列的织入设计是通过一系列Adapter来实现的。通过Adapter的设计,可以把AOP的横切面设计和Proxy模式有机结合起来,从而实现在AOP中定义好的各种织入方式。 
3、Spring AOP的应用场景 
SpringAOP把跨越应用程序多个模块的功能抽象出俩,并通过简单的AOP的使用,灵活的编制到模块中,比如可以通过AOP实现应用程序中的日志功能。另一方面,在Spring内部,一些支持模块也是通过Spring AOP来实现的,比如后面将要介绍的事务处理。下面以ProxyFactoryBean的实现为例,和大家一起来了解Spring AOP的具体设计和实现 
**三、建立AOPProxy代理对象 
1、设计原理** 
在Spring的AOP模块中,一个主要的部分是代理对象的生成,而对于Spring应用,可以看到,是通过配置和调用Spring的ProxyFactoryBean来完成这个任务的。在ProxyFactoryBean中,封装了主要代理对象的生成过程。在这个过程中,可以使用JDK的Proxy和CGLIB两种方式。 
以ProxyFactoryBean的设计为中心,可以看到相关类的继承关系: 
这里写图片描述 
2、配置ProxyFactoryBean 
我们开始进入到Spring AOP的实现部分,在分析Spring AOP的实现原理中,主要以ProxyFactoryBean的实现作为例子和实现的基本线索进行分析。这是因为ProxyFactoryBean是在Spring IOC环境中创建AOP应用的底层方法,也是最灵活的方法,Spring通过他完成了对AOP使用分封装。以ProxyFactoryBean的实现为入口,逐层深入,是一条帮助我们快速理解Spring AOP实现的学习路径。 
在了解ProxyFactoryBean的实现之前,先简要介绍下ProxyFactoryBean的配置和使用,在基于XML配置Spring的Bean时,往往需要一系列的配置补助来使用ProxyFactoryBean和AOP。 
1)定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义。这个通知器的实现定义了需要对目标对象进行增强的切面行为,也就是Advice通知。 
2)定义ProxyFactoryBean,把他作为另一个Bean来定义,他是封装AOP功能的主要类。 
3)定义target属性,作为target属性注入的Bean,是需要用AOP通知器中的切面应用来增强的对象,也就是前面提到的base对象。 
有了这些配置,就可以使用ProxyFactoryBean完成AOP的基本功能了,例如:

<bean id="testAdvisor" class="com.jader.TestAdvisor" /><bean id="testAOP" class="org.springframework.aop.ProxyFactoryBean">    <property name="proxyInterfaces">        <value>com.jader.AbcInterface</value>    </property>    <property name="interceptorNames">        <list>            <value>testAdvisor</value>        </list>    </property></bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

掌握这些配置信息后,就可以具体看一看这些AOP是如何实现的,也就是说,切面应用是怎样通过ProxyFactoryBean对target对象起作用的,下面详细分析。 
3、ProxyFactoryBean生成AOPProxy代理对象 
在Spring AOP的使用中,我们已经知道,可以通过ProxyFactoryBean来配置目标对象和切面行为。这个ProxyFactoryBean是一个FactoryBean。在ProxyFactoryBean中,通过interceptorNames属性来配置已经定义好的通知器Advisor。虽然名字为interceptorNames但实际上却是供AOP应用配置通知器的地方。在ProxyFactoryBean中,需要为target目标对象生成Proxy代理对象,从而为AOP横切面的编织做好准备工作。 
ProxyFactoryBean的AOP实现需要依赖JDK或者CGLIB提供的Proxy特性。从FactoryBean中获取对象,是以getObject方法作为入口完成的;ProxyFactoryBean实现中的getObject方法,是FactoryBean需要实现的接口。对ProxyFactoryBean来说,把需要对target目标对象增加的增强处理都通过getObject方法进行封装了。这些增强处理是为AOP功能的实现提供服务的。getObject方法首先对通知器链进行初始化,通知器链封装了一系列的拦截器,这些拦截器从配置中读取,然后为代理对象的生成做好准备。在生成代理对象时,因为Spring中有SingleTon类型和prototype类似这两种不同的Bean,所以要对代理对象的生成做一个区分。 
这里写图片描述 
getObject的代码如下:

    /**     * Return a proxy. Invoked when clients obtain beans from this factory bean.     * Create an instance of the AOP proxy to be returned by this factory.     * The instance will be cached for a singleton, and create on each call to     * {@code getObject()} for a proxy.     * @return a fresh AOP proxy reflecting the current state of this factory     */    public Object getObject() throws BeansException {        // 这里初始化通知器链        initializeAdvisorChain();        // 这里对SingleTon和prototype的类型进行区分,生成对应的proxy        if (isSingleton()) {            return getSingletonInstance();        }        else {            if (this.targetName == null) {                logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +                        "Enable prototype proxies by setting the 'targetName' property.");            }            return newPrototypeInstance();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

为Proxy代理对象配置Advisor链是在initializeAdvisorChain方法中实现的。这个初始化过程中有一个标志位AdvisorChainInitialized,这个标志用来表示通知器是否已经初始化。如果已经初始化,那么这里就会在初始化,而是直接返回。也就说,这个初始化的工作发生在应用第一次通过ProxyFactoryBean去获取代理对象的时候。在完成这个初始化之后,接着读取配置中出现的所有通知器,这个取得通知器的过程也比较简单,把通知器的名字交给容器的getBean方法就可以了,这是通过对IOC容器实现的一个回调完成的。然后把从IOC容器中取得的通知器加入到拦截器链中,这个动作是由addAdvisorOnChainCreation方法来实现的。 
下面看看对Advisor配置链的初始化:

/**     * Create the advisor (interceptor) chain. Aadvisors that are sourced     * from a BeanFactory will be refreshed each time a new prototype instance     * is added. Interceptors added programmatically through the factory API     * are unaffected by such changes.     */    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {        if (this.advisorChainInitialized) {            return;        }        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));            }            // Globals can't be last unless we specified a targetSource using the property...            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                throw new AopConfigException("Target required after globals");            }            // Materialize interceptor chain from bean names.           // 这里是添加Advisor链的调用,是通过interceptorNames属性进行配置            for (String name : this.interceptorNames) {                if (logger.isTraceEnabled()) {                    logger.trace("Configuring advisor or advice '" + name + "'");                }                if (name.endsWith(GLOBAL_SUFFIX)) {                    if (!(this.beanFactory instanceof ListableBeanFactory)) {                        throw new AopConfigException(                                "Can only use global advisors or interceptors with a ListableBeanFactory");                    }                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));                }                else {                    // If we get here, we need to add a named interceptor.                    // We must check if it's a singleton or prototype.                    // 如果程序在这里被调用,那么需要加入命名的拦截器advice,并且需要检查这个Bean是SingleTon还是prototype类型                    Object advice;                    if (this.singleton || this.beanFactory.isSingleton(name)) {                        // Add the real Advisor/Advice to the chain.                        advice = this.beanFactory.getBean(name);                    }                    else {                        // It's a prototype Advice or Advisor: replace with a prototype.                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.                        advice = new PrototypePlaceholderAdvisor(name);                    }                    addAdvisorOnChainCreation(advice, name);                }            }        }        this.advisorChainInitialized = true;    }

生成SingleTon代理对象在getSingleTonInstance方法中完成,这个方法时ProxyFactoryBean生成AopProxy对象的入口。代理对象会封装对target目标对象的调用,也就是说针对target对象的方法调用行为会被这里生成的代理对象所拦截。具体的生成过程是首先读取ProxyFactoryBean配置,为生成代理对象做好准备。Spring通过AopProxy类来具体生成代理对象。对于getSingleTonInstance方法中生成代理对象的过程如下:

/**     * Return the singleton instance of this class's proxy object,     * lazily creating it if it hasn't been created already.     * @return the shared singleton proxy     */    private synchronized Object getSingletonInstance() {        if (this.singletonInstance == null) {            this.targetSource = freshTargetSource();            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {                // Rely on AOP infrastructure to tell us what interfaces to proxy.                // 根据AOP框架来判断需要代理的接口                Class targetClass = getTargetClass();                if (targetClass == null) {                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");                }                // 这里设置代理对象的接口                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));            }            // Initialize the shared singleton instance.            super.setFrozen(this.freezeProxy);            // 这里会使用ProxyFactoryBean来生成需要的proxy对象            this.singletonInstance = getProxy(createAopProxy());        }        return this.singletonInstance;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
/**     * Return the proxy object to expose.     * <p>The default implementation uses a {@code getProxy} call with     * the factory's bean class loader. Can be overridden to specify a     * custom class loader.     * @param aopProxy the prepared AopProxy instance to get the proxy from     * @return the proxy object to expose     * @see AopProxy#getProxy(ClassLoader)     */    protected Object getProxy(AopProxy aopProxy) {        return aopProxy.getProxy(this.proxyClassLoader);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这里出现了AopProxy对象类型,Spring利用AOPProxy接口类把AOP代理对象的实现与框架其他部分有效隔离开来。AopProxy接口有两个子类实现,一个Cglib2AopProxy,另一个是JdkDynamicProxy。 
具体代理对象的生成是在ProxyFactoryBean的基类AdvisedSupport中实现,借助AopProxyFactory完成,这个对象要么从JDK中生成,要么借助CGLIB获得。下面看看ProxyCreatorSupport中是如何生成代理对象的。

    /**     * Subclasses should call this to get a new AOP proxy. They should <b>not</b>     * create an AOP proxy with {@code this} as an argument.     */    protected final synchronized AopProxy createAopProxy() {        if (!this.active) {            activate();        }        // 通过AopProxyFactory取得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory        return getAopProxyFactory().createAopProxy(this);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

AopProxy代理对象的生成有两种方式,如果目标对象是接口类使用JDK来生成,否则Spring会使用CGLIB来生成目标的代理对象。下面看看在DefaultAopProxyFactory是如何生成AopProxy目标代理对象的:

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {        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.");            }            if (targetClass.isInterface()) {                return new JdkDynamicAopProxy(config);            }            return CglibProxyFactory.createCglibProxy(config);        }        else {            return new JdkDynamicAopProxy(config);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在AopProxy代理对象的生成过程中,首先要从AdviseSupport对象中取得配置的目标对象,AOP完成的是切面应用对目标应用对象的增强。如果这里没有配置目标对象会直接抛出异常。一般而言,默认方式是使用JDK来产生AopProxy代理对象,但如果配置的目标对象不是接口类的实现,会使用CGLIB来产生AopProxy代理对象;在使用CGLIB来产生AopProxy代理对象时,因为CGLIB是第三方类库,本身不在JDK基类库中,所有需要在classPath中正确配置,以便能够加载和利用。在Spring中,使用JDK和CGLIB来生成AopProxy代理对象的工作,是由JdkDynamicAopProxy和CglibProxyFactory来完成。 
4、JDK生成AopProxy对象(接口实现类) 
通过上面我们已经知道生成AopProxy对象有两种方式,下面看下类图: 
这里写图片描述 
我们先看下JdkDynamicAopProxy是如何生成AopProxy对象的:

    public Object getProxy(ClassLoader classLoader) {        if (logger.isDebugEnabled()) {            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());        }        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);        // 调用JDK生成Proxy        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5、CGLIB生成AopProxy对象(非接口实现类)

    public Object getProxy(ClassLoader classLoader) {        if (logger.isDebugEnabled()) {            logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());        }        try {            Class<?> rootClass = this.advised.getTargetClass();            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");            Class<?> proxySuperClass = rootClass;            if (ClassUtils.isCglibProxyClass(rootClass)) {                proxySuperClass = rootClass.getSuperclass();                Class<?>[] additionalInterfaces = rootClass.getInterfaces();                for (Class<?> additionalInterface : additionalInterfaces) {                    this.advised.addInterface(additionalInterface);                }            }            // Validate the class, writing log messages as necessary.            validateClassIfNecessary(proxySuperClass);            // Configure CGLIB Enhancer...            // 来自advised的IOC配置,比如使用AOP的DynamicAdvisedInterceptor            Enhancer enhancer = createEnhancer();            if (classLoader != null) {                enhancer.setClassLoader(classLoader);                if (classLoader instanceof SmartClassLoader &&                        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {                    enhancer.setUseCache(false);                }            }            enhancer.setSuperclass(proxySuperClass);            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);            enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));            enhancer.setInterceptDuringConstruction(false);            // 通过设置DynamicAdvisedInterceptor拦截器来完成AOP功能,getCallBacks方法如下:            // Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised)            Callback[] callbacks = getCallbacks(rootClass);            Class<?>[] types = new Class<?>[callbacks.length];            for (int x = 0; x < types.length; x++) {                types[x] = callbacks[x].getClass();            }            enhancer.setCallbackFilter(new ProxyCallbackFilter(                    this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));            enhancer.setCallbackTypes(types);            enhancer.setCallbacks(callbacks);            // Generate the proxy class and create a proxy instance.            Object proxy;            if (this.constructorArgs != null) {                proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);            }            else {                proxy = enhancer.create();            }            return proxy;        }        catch (CodeGenerationException ex) {            throw new AopConfigException("Could not generate CGLIB subclass of class [" +                    this.advised.getTargetClass() + "]: " +                    "Common causes of this problem include using a final class or a non-visible class",                    ex);        }        catch (IllegalArgumentException ex) {            throw new AopConfigException("Could not generate CGLIB subclass of class [" +                    this.advised.getTargetClass() + "]: " +                    "Common causes of this problem include using a final class or a non-visible class",                    ex);        }        catch (Exception ex) {            // TargetSource.getTarget() failed            throw new AopConfigException("Unexpected AOP exception", ex);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

四、Spring AOP拦截器调用的实现 
1、设计原理 
在Spring AOP通过JDK的Proxy方式或CGLIB方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中起作用是通过对这些方法的回调来完成的。 
如果使用JDK的Proxy来生成代理对象,那么需要InvocationHandler来设置拦截器回调,而如果使用CGLIB来生成代理对象,通过DynamicAdvisedInterceptor来完成回调。 
2、JdkDynamicAopProxy的invoke拦截 
在JDKDynamicAopProxy生成代理对象时,他的AopProxy代理对象生成调用:

Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  • 1

this指的是InvocationHandler对象,InvocationHandler是JDK定义反射类的一个接口,这个接口定义了invoke方法,此方法为回调方法。通过invoke的具体实现,来完成对目标对象方法调用的拦截器或者功能增强工作。在这个方法中,包含一个完整的拦截器链对目标对象的拦截过程,比如获取拦截器链中的拦截器进行配置,逐个运行拦截器链里的拦截器增强,知道最后的目标对象方法的运行。下面看下invoke的源码

    /**     * Implementation of {@code InvocationHandler.invoke}.     * <p>Callers will see exactly the exception thrown by the target,     * unless a hook method throws an exception.     */    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        MethodInvocation invocation;        Object oldProxy = null;        boolean setProxyContext = false;        TargetSource targetSource = this.advised.targetSource;        Class<?> targetClass = null;        Object target = null;        try {            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {                // The target does not implement the equals(Object) method itself.                return equals(args[0]);            }            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {                // The target does not implement the hashCode() method itself.                return hashCode();            }            if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {                // Service invocations on ProxyConfig with the proxy config...                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);            }            Object retVal;            if (this.advised.exposeProxy) {                // 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.            // 如果没有拦截器直接调用target的对应方法            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.                // 如果有拦截器设定,那么需要调用拦截器之后才调用目标对象相应的方法                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);            }            else {                // 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();            if (retVal != null && retVal == target && 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()) {                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.releaseTarget(target);            }            if (setProxyContext) {                // Restore old proxy.                AopContext.setCurrentProxy(oldProxy);            }        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

3、CglibAopProxy的intercept拦截器 
使用CglibAopProxy生成AopProxy对象时候,对于AOP拦截器调用,回调的是DynamicAdvisedInterceptor对象生成的。回调的方法时intercept,下面看看回调方法的源码:

        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {            Object oldProxy = null;            boolean setProxyContext = false;            Class<?> targetClass = null;            Object target = null;            try {                if (this.advised.exposeProxy) {                    // 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 = getTarget();                if (target != null) {                    targetClass = target.getClass();                }                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);                Object retVal;                // Check whether we only have one InvokerInterceptor: that is,                // no real advice, but just reflective invocation of the target.                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {                    // 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.                    retVal = methodProxy.invoke(target, args);                }                else {                    // We need to create a method invocation...                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();                }                retVal = processReturnType(proxy, target, method, retVal);                return retVal;            }            finally {                if (target != null) {                    releaseTarget(target);                }                if (setProxyContext) {                    // Restore old proxy.                    AopContext.setCurrentProxy(oldProxy);                }            }        }

4、目标方法的调用 
如果没有拦截器会对目标对象方法直接调用。对于JDKDynamicAopProxy代理对象是通过AopUtils使用反射机制实现的。在这个调用方法中首先得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。源码如下:

    /**     * Invoke the given target via reflection, as part of an AOP method invocation.     * @param target the target object     * @param method the method to invoke     * @param args the arguments for the method     * @return the invocation result, if any     * @throws Throwable if thrown by the target method     * @throws org.springframework.aop.AopInvocationException in case of a reflection error     */    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)            throws Throwable {        // Use reflection to invoke the method.        try {            ReflectionUtils.makeAccessible(method);            return method.invoke(target, args);        }        catch (InvocationTargetException ex) {            // Invoked method threw a checked exception.            // We must rethrow it. The client won't see the interceptor.            throw ex.getTargetException();        }        catch (IllegalArgumentException ex) {            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +                    method + "] on target [" + target + "]", ex);        }        catch (IllegalAccessException ex) {            throw new AopInvocationException("Could not access method [" + method + "]", ex);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

5、AOP拦截器的调用 
下面进入AOP的核心部分,Aop是怎样完成对目标的增强的。这些都封装在Aop拦截器链中,由一个具体的拦截器完成。 
无论是使用JDKDynamicAopProxy还是使用CglibAopProxy创建代理对象最终对AOP拦截链的调用都是在ReflectiveMethodInvocation中通过proceed方法实现的。在proceed方法中逐个运行拦截器的拦截方法。在运行拦截器的拦截方法之前需要对代理方法完成一个匹配,通过这个匹配判断来决定拦截器是否满足切面增强的要求。具体代码如下:

    public Object proceed() throws Throwable {        //  We start with an index of -1 and increment early.        // 从索引为-1的拦截器开始调用,并按序递增        // 如果拦截器链里的拦截器迭代调用完毕,这里开始调用target函数,这个函数是通过反射机制完成        // 具体在AopUtils.invokeJoinpointUsingReflection方法中完成        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {            return invokeJoinpoint();        }        // 这里沿着定义好的interceptorOrInterceptionAdvice链进行处理        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.            // 前面分析的Pointcut,这里是触发匹配的地方,如果定义的Pointcut匹配,那么这个advice将会得到执行            InterceptorAndDynamicMethodMatcher dm =                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;            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.                // 如果不匹配,proceed会递归调用,知道所有的拦截器被运行                return proceed();            }        }        else {            // It's an interceptor, so we just invoke it: The pointcut will have            // been evaluated statically before this object was constructed.            // 如果是一个拦截器,直接调用这个interceptor对应的方法            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

这时我们会有疑问,这些advisor是怎样从配置文件中获得并配置到proxy的拦截器链中,我们使用的advisor通知时怎样起作用的,让我们带着这些问题继续往下看。 
6、配置通知器 
在整个AopProxy代理对象拦截回调过程中,先回到ReflectionMethodInvocation类的proceed方法,在这个方法里,可以看到得到了配置的interceptorOrInterceptionAdvice,如下所示:

Object interceptorOrInterceptionAdvice =                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  • 1
  • 2

interceptorOrInterceptionAdvice是获得的拦截器,他通过拦截器机制对目标对象进行增强。这个拦截器来自interceptorsAndDynamicMethodMatchers。具体来说,他是interceptorsAndDynamicMathers持有的List中的一个元素。关于如何配置拦截器的问题就转化为了List中的拦截器元素是从哪里来的,在哪里配置的问题。接着对invoke调用进行回放,回到JDKDynamicAopProxy中的invoke方法中,可以看到这个List中的interceptors是从哪个调用中获取的。对于CglibAopProxy,也有类似过程,只不过这个过程是在DynamicAdvisedInterceptor的intercept回调中实现的,如下所示:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);
  • 1

从上面的代码可以看出,获取intercptors的操作是由advised对象完成的,这个advised是一个AdvisedSupport对象,从AdvisedSupport类中可以看到getInterceptorsAndDynamicInterceptionAdvice的实现。在这个方法中取得了拦截器链,再取得拦截器链的时候,为了提高拦截器链的效率,还为这个拦截器链这是了缓存。

    /**     * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects     * for the given method, based on this configuration.     * @param method the proxied method     * @param targetClass the target class     * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)     */    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {        // 这里使用cache,利用cache去获取已有的inteceptor链,但是第一次还是需要自己动手生成的。这个inteceptor链的生成        // 是由advisorChainFactory完成的,在这里使用的是DefaultAdvisorChainFactory        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;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在 DefaultAdvisorChainFactory中实现了interceptor链的获取过程,在这个过程中,首先设置了一个List,其长度是配置的通知器的个数来决定的,这个配置时在XML中对ProxyFactoryBean做的interceptNames属性的配置,然后,DefaultAdvisorChainFactory会通过一个AdvisorAdapterRegistry来实现拦截器的注册。AdvisorAdapterRegistry对advice通知的织入功能起了很大作用。有了AdvisorAdapterRegistry注册器,利用他来对ProxyFactoryBean配置中得到的通知进行适配,从而得到相应的拦截器,再把他前面设置好的List中去,完成所谓的拦截器注册过程。在拦截器适配和注册过程完成以后,List中的拦截器会被JDK生成的AopProxy代理对象的invoke方法或者CGLIB代理对象的intercept拦截方法获得,并启动拦截器的invoke方法调用,最终触发通知的切面增强。 
下面看看DefaultAdvisorChainFactory是怎样生成拦截器链的:

/** * A simple but definitive way of working out an advice chain for a Method, * given an {@link Advised} object. Always rebuilds each advice chain; * caching can be provided by subclasses. * * @author Juergen Hoeller * @author Rod Johnson * @author Adrian Colyer * @since 2.0.3 */@SuppressWarnings("serial")public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {    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.        // advisor链已经在config中持有了,这里可以直接使用        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);        boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();        for (Advisor advisor : config.getAdvisors()) {            if (advisor instanceof PointcutAdvisor) {                // Add it conditionally.                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {                    // 拦截器链是通过AdvisorAdapterRegistry来加入的,这个AdvisorAdapterRegistry                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();                    if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {                        if (mm.isRuntime()) {                            // 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));                            }                        }                        else {                            interceptorList.addAll(Arrays.asList(interceptors));                        }                    }                }            }            else if (advisor instanceof IntroductionAdvisor) {                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;                if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {                    Interceptor[] interceptors = registry.getInterceptors(advisor);                    interceptorList.addAll(Arrays.asList(interceptors));                }            }            else {                Interceptor[] interceptors = registry.getInterceptors(advisor);                interceptorList.addAll(Arrays.asList(interceptors));            }        }        return interceptorList;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
    /**     * Determine whether the Advisors contain matching introductions.     */    // 判断Advisors是否符合要求    private static boolean hasMatchingIntroductions(Advised config, Class targetClass) {        for (int i = 0; i < config.getAdvisors().length; i++) {            Advisor advisor = config.getAdvisors()[i];            if (advisor instanceof IntroductionAdvisor) {                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;                if (ia.getClassFilter().matches(targetClass)) {                    return true;                }            }        }        return false;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在ProxyFactoryBean的getObject方法中对adviosr进行初始化,从XML配置中获取了advisor通知器。下面看下在ProxyFactoryBean拦截器链的初始化中获取advisor通知器

    /**     * Create the advisor (interceptor) chain. Aadvisors that are sourced     * from a BeanFactory will be refreshed each time a new prototype instance     * is added. Interceptors added programmatically through the factory API     * are unaffected by such changes.     */    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {        if (this.advisorChainInitialized) {            return;        }        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));            }            // Globals can't be last unless we specified a targetSource using the property...            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                throw new AopConfigException("Target required after globals");            }            // Materialize interceptor chain from bean names.            for (String name : this.interceptorNames) {                if (logger.isTraceEnabled()) {                    logger.trace("Configuring advisor or advice '" + name + "'");                }                if (name.endsWith(GLOBAL_SUFFIX)) {                    if (!(this.beanFactory instanceof ListableBeanFactory)) {                        throw new AopConfigException(                                "Can only use global advisors or interceptors with a ListableBeanFactory");                    }                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));                }                else {                    // If we get here, we need to add a named interceptor.                    // We must check if it's a singleton or prototype.                    Object advice;                    if (this.singleton || this.beanFactory.isSingleton(name)) {                        // Add the real Advisor/Advice to the chain.                        // 这里是取得advisor的地方,是通过BeanFactory取得的                        // 把interceptorNames这个List中interceptor名字交给                        // BeanFactory,然后通过调用BeanFactory的getBean去获取                        advice = this.beanFactory.getBean(name);                    }                    else {                        // It's a prototype Advice or Advisor: replace with a prototype.                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.                        advice = new PrototypePlaceholderAdvisor(name);                    }                    addAdvisorOnChainCreation(advice, name);                }            }        }        this.advisorChainInitialized = true;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

advisor通知器的取得时委托给IOC容器完成的,但是在ProxyFactoryBean中是如何获得IOC容器,然后通过回调IOC容器的getBean方法来得到需要的通知advisor?在这里大家可以回顾下IOC容器的原理.

7、Advice通知的实现 
AopProxy代理对象生成时,其拦截器也一并生成。下面我们来分析下Aop是如何对目标对象进行增强的。在为AopProxy配置拦截器的实现中,有一个取得拦截器配置过程,这个过程由DefaultAvisorChainFactory实现的,而这个工厂类负责生成拦截器链,在它的getInterceptorsAndDynamicInterceptionA- 
dvice方法中,有一个适配器的注册过程,通过配置Spring预先设计好的拦截器,Spring加入了它对Aop实现的处理。为详细了解这个过程,先从Defau- 
ltAdvisorChainFactory的实现开始,通过以下代码可以看到,在DefaultAdvisorChainFactory实现中,首先构造了一个GlobalAdvisorAdapterRegistry单件,然后对配置的Advisor通知器进行逐个遍历,这些通知链都是配置在interceptorNames中的,从getInterceptorsAndDynamicInterceptionAdvice传递进来的advised参数对象中,可以方便的取得配置的通知器,有了这些通知器,接着就是一个由 
GlobalAdvisorAdapterRegistry来完成的拦截器的适配和注册。

/** * A simple but definitive way of working out an advice chain for a Method, * given an {@link Advised} object. Always rebuilds each advice chain; * caching can be provided by subclasses. * @author Juergen Hoeller * @author Rod Johnson * @author Adrian Colyer * @since 2.0.3 */@SuppressWarnings("serial")public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {    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);        boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);        // 得到注册器GlobalAdvisorAdapterRegistry,这是一个单件模式的实现        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();        for (Advisor advisor : config.getAdvisors()) {            if (advisor instanceof PointcutAdvisor) {                // Add it conditionally.                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();                    if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {                        if (mm.isRuntime()) {                            // 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));                            }                        }                        else {                            interceptorList.addAll(Arrays.asList(interceptors));                        }                    }                }            }            else if (advisor instanceof IntroductionAdvisor) {                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;                if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {                    Interceptor[] interceptors = registry.getInterceptors(advisor);                    interceptorList.addAll(Arrays.asList(interceptors));                }            }            else {                Interceptor[] interceptors = registry.getInterceptors(advisor);                interceptorList.addAll(Arrays.asList(interceptors));            }        }        return interceptorList;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

GlobalAdvisorAdapterRegistry的getInterceptors方法为AOP的实现做出了很大的贡献,这个方法封装着advice织入实现的入口,我们先从GlobalAdvisorAdapterRegistry的实现入手,他基本起一个适配器的作用,但同时也是单件模式,代码如下:

     /**     * Keep track of a single instance so we can return it to classes that request it.     */    // 使用静态变量来保持一个唯一实例    private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();    /**     * Return the singleton {@link DefaultAdvisorAdapterRegistry} instance.     */    public static AdvisorAdapterRegistry getInstance() {        return instance;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

到这里,我们知道在DefaultAdvisorAdapterRegistry中,设置了一系列的adapter适配器,这是这些适配器的实现,为Spring的advice提供了编织能力,下面我们看看DefaultAdvisorAdapterRegistry究竟发生了什么?adapter的作用具体分为两个: 
1、调用adapter的support方法,通过这个方法来判断取得的advice属于什么类型的advice通知,从而根据不同的advice类型来注册不同的AdviceInterceptor,也就是前面我们看到的拦截器 
2、这些AdviceInterceptor都是Spring AOP框架设计好的,是为实现不同的advice功能提供服务的。有了这些AdviceInterceptor,可以方便的使用由Spring提供的各种不同的advice来设计AOP应用。也就是说,正是这些AdviceInterceptor最终实现了advice通知在AopProxy对象中的织入功能。

/** * Default implementation of the {@link AdvisorAdapterRegistry} interface. * Supports {@link org.aopalliance.intercept.MethodInterceptor}, * {@link org.springframework.aop.MethodBeforeAdvice}, * {@link org.springframework.aop.AfterReturningAdvice}, * {@link org.springframework.aop.ThrowsAdvice}. * * @author Rod Johnson * @author Rob Harrop * @author Juergen Hoeller */@SuppressWarnings("serial")public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {    private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);    /**     * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.     */    public DefaultAdvisorAdapterRegistry() {        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());        registerAdvisorAdapter(new AfterReturningAdviceAdapter());        registerAdvisorAdapter(new ThrowsAdviceAdapter());    }    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {        if (adviceObject instanceof Advisor) {            return (Advisor) adviceObject;        }        if (!(adviceObject instanceof Advice)) {            throw new UnknownAdviceTypeException(adviceObject);        }        Advice advice = (Advice) adviceObject;        if (advice instanceof MethodInterceptor) {            // So well-known it doesn't even need an adapter.            return new DefaultPointcutAdvisor(advice);        }        for (AdvisorAdapter adapter : this.adapters) {            // Check that it is supported.            if (adapter.supportsAdvice(advice)) {                return new DefaultPointcutAdvisor(advice);            }        }        throw new UnknownAdviceTypeException(advice);    }    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(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[interceptors.size()]);    }    public void registerAdvisorAdapter(AdvisorAdapter adapter) {        this.adapters.add(adapter);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

剥茧抽丝,继续看adapter,在DefaultAdvisorRegistry的getInterceptors调用中,从MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdaper这几个通知适配器的名字上可以看出和Advice一一对应,在这里,他们作为适配器被加入到adapter的List中,他们都是实现AdvisorAdapter接口的同一层次的类,只是各自承担着不同的适配的任务,一对一的服务于不同的advice实现。 
以MethodBeforeAdviceAdapter为例,代码如下:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {    public boolean supportsAdvice(Advice advice) {        return (advice instanceof MethodBeforeAdvice);    }    // 把advice从通知器中取出    public MethodInterceptor getInterceptor(Advisor advisor) {        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();        return new MethodBeforeAdviceInterceptor(advice);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

到这里就非常清楚了,Spring AOP为了实现advice的织入,设计了特定拦截器对这些功能进行了封装。虽然应用不会直接用到这些拦截器,但却是advice发挥作用不可缺少的准备。还是以MethodBeforeAdviceInterceptor为例,我们看看advice是如何封装的。在invoke回调方法中,看到首先触发了advice的before的回调,然后才是MethodInvocation的proceed方法的调用。看到这里,就已经和前面的在ReflectionMethodInvocation的Proceed分析中联系起来。回忆了一下,在AopProxy代理对象触发的ReflectionMethodInvocation的proceed方法中,在取得拦截器以后,启动了对拦截器invoke方法的调用。按照AOP的规则,ReflectiveMethodInvocation触发的拦截器invoke方法,最终会根据不同的advice类型,触发Spring对不同的advice的拦截器封装,比如对MethodBeforeAdvice,最终会根据不同的advice类型触发Spring对不同的advice的拦截器封装。比如对MethodBeforeAdvice,最终会触发MethodBeforeAdviceInterceptor的invoke方法。在MethodBeforeAdviceInterceptor方法中,会调用advice的before方法,这就是MethodBeforeAdvice所需要的对目标对象的增强效果:在方法调用之前通知增强。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {    private MethodBeforeAdvice advice;    /**     * Create a new MethodBeforeAdviceInterceptor for the given advice.     * @param advice the MethodBeforeAdvice to wrap     */    // 为指定的Advice创建对应的MethodBeforeAdviceInterceptor对象    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {        Assert.notNull(advice, "Advice must not be null");        this.advice = advice;    }    // 这个invoke方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调    public Object invoke(MethodInvocation mi) throws Throwable {        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );        return mi.proceed();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

完成MethodBeforeAdviceInterceptor的调用,然后启动advice通知的afterReturning回调,代码如下:

/**     * Create a new AfterReturningAdviceInterceptor for the given advice.     * @param advice the AfterReturningAdvice to wrap     */    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {        Assert.notNull(advice, "Advice must not be null");        this.advice = advice;    }    public Object invoke(MethodInvocation mi) throws Throwable {        Object retVal = mi.proceed();        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());        return retVal;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

ThrowsAdvice的实现和上面类似,也是封装在对应的AdviceInterceptor中,ThrowsAdvice的回调方法要复杂一些,他维护了一个exceptionHandlerMap来对应不同的方法调用场景,这个exceptionHandlerMap中的handler的取得时与触发ThrowsAdvice增强的异常相关的。

/** * Interceptor to wrap an after-throwing advice. * * <p>The signatures on handler methods on the {@code ThrowsAdvice} * implementation method argument must be of the form:<br> * * {@code void afterThrowing([Method, args, target], ThrowableSubclass);} * * <p>Only the last argument is required. * * <p>Some examples of valid methods would be: * * <pre class="code">public void afterThrowing(Exception ex)</pre> * <pre class="code">public void afterThrowing(RemoteException)</pre> * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, Exception ex)</pre> * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)</pre> * * <p>This is a framework class that need not be used directly by Spring users. * * @author Rod Johnson * @author Juergen Hoeller */public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {    private static final String AFTER_THROWING = "afterThrowing";    private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);    private final Object throwsAdvice;    /** Methods on throws advice, keyed by exception class */    private final Map<Class, Method> exceptionHandlerMap = new HashMap<Class, Method>();    /**     * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.     * @param throwsAdvice the advice object that defines the exception     * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice}     * implementation)     */    public ThrowsAdviceInterceptor(Object throwsAdvice) {        Assert.notNull(throwsAdvice, "Advice must not be null");        this.throwsAdvice = throwsAdvice;        // 配置ThrowsAdvice回调方法        Method[] methods = throwsAdvice.getClass().getMethods();        for (Method method : methods) {            if (method.getName().equals(AFTER_THROWING) &&                    (method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &&                    Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1])                ) {                // Have an exception handler                // 配置异常处理                this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method);                if (logger.isDebugEnabled()) {                    logger.debug("Found exception handler method: " + method);                }            }        }        if (this.exceptionHandlerMap.isEmpty()) {            throw new IllegalArgumentException(                    "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");        }    }    public int getHandlerMethodCount() {        return this.exceptionHandlerMap.size();    }    /**     * Determine the exception handle method. Can return null if not found.     * @param exception the exception thrown     * @return a handler for the given exception type     */    private Method getExceptionHandler(Throwable exception) {        Class exceptionClass = exception.getClass();        if (logger.isTraceEnabled()) {            logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");        }        Method handler = this.exceptionHandlerMap.get(exceptionClass);        while (handler == null && !exceptionClass.equals(Throwable.class)) {            exceptionClass = exceptionClass.getSuperclass();            handler = this.exceptionHandlerMap.get(exceptionClass);        }        if (handler != null && logger.isDebugEnabled()) {            logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);        }        return handler;    }    public Object invoke(MethodInvocation mi) throws Throwable {        try {            // 把目标对象方法调用放在try catch中,并在catch中触发,            // ThrowsAdvice的回调,把异常接着向外抛出,不做过多的处理            return mi.proceed();        }        catch (Throwable ex) {            Method handlerMethod = getExceptionHandler(ex);            if (handlerMethod != null) {                invokeHandlerMethod(mi, ex, handlerMethod);            }            throw ex;        }    }    // 通过反射启动对ThrowsAdvice回调方法的调用    private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {        Object[] handlerArgs;        if (method.getParameterTypes().length == 1) {            handlerArgs = new Object[] { ex };        }        else {            handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};        }        try {            method.invoke(this.throwsAdvice, handlerArgs);        }        catch (InvocationTargetException targetEx) {            throw targetEx.getTargetException();        }    }}



  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
原创粉丝点击