您的位置 首页 >  博文

Spring源码解析之Spring AOP 获取 Proxy

下面我们来看看 Spring 的 AOP 的一些相关代码是怎么得到 Proxy 的,让我们我们先看看 AOP 和 Spring AOP 的一些基本概念:
Advice:
通知,制定在连接点做什么,在 Sping 中,他主要描述 Spring 围绕方法调用注入的额外的行为,Spring 提供的通知类型有:

1before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice

这些都是 Spring AOP 定义的接口类,具体的动作实现需要用户程序来完成。
Pointcut:
切点,其决定一个 advice 应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个 advice 作为目标的一组方法。Spring pointcut 通常意味着标示方法,可以选择一组方法调用作为 pointcut,Spring 提供了具体的切点来给用户使用,比如正则表达式切点 JdkRegexpMethodPointcut 通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut 中的对MethodMatcher 接口的实现来完成 pointcut 功能:

 1public final boolean matches(Method method, Class targetClass) 
2    //这里通过反射得到方法的全名 
3    String patt = method.getDeclaringClass().getName() + "." + method.getName(); 
4    for (int i = 0; i < this.patterns.length; i++) { 
5        // 这里是判断是否和方法名是否匹配的代码 
6        boolean matched = matches(patt, i); 
7        if (matched) { 
8            for (int j = 0; j < this.excludedPatterns.length; j++) { 
9                boolean excluded = matchesExclusion(patt, j); 
10                if(excluded) { 
11                    return false
12                } 
13            } 
14            return true
15        } 
16    } 
17    return false
18

在 JDKRegexpMethodPointcut 中通过 JDK 中的正则表达式匹配来完成 pointcut 的最终确定:

1protected boolean matches(String pattern, int patternIndex) 
2    Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern); 
3    return matcher.matches(); 
4

Advisor:
当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 - advisor,定义应该在哪里应用哪个通知。Advisor 的实现有:DefaultPointcutAdvisor 他有两个属性 advice 和 pointcut 来让我们配置 advice和 pointcut。

接着我们就可以通过 ProxyFactoryBean 来配置我们的代理对象和方面行为,在 ProxyFactoryBean 中有 interceptorNames 来配置已经定义好的通知器-advisor,虽然这里的名字叫做 interceptNames,但实际上是供我们配置 advisor 的地方,具体的代理实现通过 JDK 的Proxy 或者 CGLIB 来完成。因为 ProxyFactoryBean 是一个 FactoryBean,在 ProxyFactoryBean 中我们通过 getObject()可以直接得到代理对象:

 1public Object getObject() throws BeansException 
2    //这里初始化通知器链 
3    initializeAdvisorChain(); 
4    if (isSingleton()) { 
5        //根据定义需要生成单件的 Proxy 
6        return getSingletonInstance(); 
7    }else { 
8        ...
9        //这里根据定义需要生成 Prototype 类型的 Proxy 
10        return newPrototypeInstance(); 
11    } 
12

我们看看怎样生成单件的代理对象:

 1private synchronized Object getSingletonInstance() 
2    if (this.singletonInstance == null) { 
3        this.targetSource = freshTargetSource(); 
4        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { 
5            // 这里设置代理对象的接口 
6            setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass())); 
7        } 
8        // Eagerly initialize the shared singleton instance. 
9        super.setFrozen(this.freezeProxy); 
10        // 注意这里的方法会使用 ProxyFactory 来生成我们需要的 Proxy 
11        this.singletonInstance = getProxy(createAopProxy()); 
12        // We must listen to superclass advice change events to recache the singleton 
13        // instance if necessary. 
14        addListener(this); 
15    } 
16    return this.singletonInstance; 
17
18
19//使用 createAopProxy 放回的 AopProxy 来得到代理对象。 
20protected Object getProxy(AopProxy aopProxy) 
21    return aopProxy.getProxy(this.beanClassLoader); 
22

ProxyFactoryBean 的父类是 AdvisedSupport,Spring 使用 AopProxy 接口把 AOP 代理的实现与框架的其他部分分离开来;在AdvisedSupport 中通过这样的方式来得到 AopProxy,当然这里需要得到 AopProxyFactory 的帮助 - 下面我们看到 Spring 为我们提供的实现,来帮助我们方便的从 JDK 或者 cglib 中得到我们想要的代理对象:

1protected synchronized AopProxy createAopProxy() 
2    if (!this.isActive) { 
3        activate(); 
4    } 
5    return getAopProxyFactory().createAopProxy(this); 
6

而在 ProxyConfig 中对使用的 AopProxyFactory 做了定义:

1//这个 DefaultAopProxyFactory 是 Spring 用来生成 AopProxy 的地方, 
2//当然了它包含 JDK 和 Cglib 两种实现方式。 
3private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory(); 

其中在 DefaultAopProxyFactory 中是这样生成 AopProxy 的:

 1public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException 
2    //首先考虑使用 cglib 来实现代理对象,当然如果同时目标对象不是接口的实现类的话 
3    if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() || 
4        advisedSupport.getProxiedInterfaces().length == 0) { 
5        //这里判断如果不存在 cglib 库,直接抛出异常。 
6        if (!cglibAvailable) { 
7            throw new AopConfigException( 
8            "Cannot proxy target class because CGLIB2 is not available. " + 
9            "Add CGLIB to the class path or specify proxy interfaces."); 
10        } 
11        // 这里使用 Cglib 来生成 Proxy,如果 target 不是接口的实现的话,返回 cglib 类型的 AopProxy 
12        return CglibProxyFactory.createCglibProxy(advisedSupport); 
13    } 
14    else { 
15        // 这里使用 JDK 来生成 Proxy,返回 JDK 类型的 AopProxy 
16        return new JdkDynamicAopProxy(advisedSupport); 
17    } 
18

于是我们就可以看到其中的代理对象可以由 JDK 或者 Cglib 来生成,我们看到 JdkDynamicAopProxy 类和 Cglib2AopProxy 都实现的是AopProxy 的接口,在 JdkDynamicAopProxy 实现中我们可以看到 Proxy 是怎样生成的:

 1public Object getProxy(ClassLoader classLoader) 
2    if (logger.isDebugEnabled()) { 
3        Class targetClass = this.advised.getTargetSource().getTargetClass(); 
4        logger.debug("Creating JDK dynamic proxy" + 
5        (targetClass != null ? " for [" + targetClass.getName() + "]" : "")); 
6    } 
7    Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); 
8    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); 
9    //这里我们调用 JDK Proxy 来生成需要的 Proxy 实例 
10    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 
11

这样用 Proxy 包装 target 之后,通过 ProxyFactoryBean 得到对其方法的调用就被 Proxy 拦截了, ProxyFactoryBean 的 getObject()方法得到的实际上是一个 Proxy 了,我们的 target 对象已经被封装了。对 ProxyFactoryBean 这个工厂 bean 而言,其生产出来的对象是封装了目标对象的代理对象


关于作者: 王俊南(Jonas)

昨夜寒蛩不住鸣。惊回千里梦,已三更。起来独自绕阶行。人悄悄,帘外月胧明。 白首为功名。旧山松竹老,阻归程。欲将心事付瑶琴。知音少,弦断有谁听。

热门文章