Spring技术内幕:深入解析Spring架构与设计原理(第2版)
上QQ阅读APP看书,第一时间看更新

3.5 Spring AOP的高级特性

了解了Spring AOP的基本实现,下面通过一个使用Spring AOP高级特性的例子,来了解它的实现原理。在使用Spring AOP时,对目标对象的增强是通过拦截器来完成的。对于一些应用场合,需要对目标对象本身进行一些处理,比如,如何从一个对象池或对象工厂中获得目标对象等。对于这种情况,需要使用Spring的TargetSource接口特性,在这里,把这类AOP特性当成高级特性的一种,通过对这些AOP特性的实现原理的了解,可以实现对AOP基本特性的灵活运用。

Spring提供了许多现成的TargetSource实现,比如HotSwappableTargetSource,HotSwappableTargetSource使用户可以以线程安全的方式切换目标对象,提供所谓的热交换功能。这个特性是很有用的,尽管它的开启需要AOP应用进行显式的配置,但配置并不复杂,在使用时,只需要把HotSwappableTargetSource配置到ProxyFactoryBean的target属性就可以了,在需要更换真正的目标对象时,调用HotSwappableTargetSource的swap方法就可以完成。由此可见,对HotSwappableTargetSource的热交换功能的使用,是需要触发swap方法调用的。这个swap方法的实现很简单,它完成target对象的替换,也就是说,它使用新的target对象来替换原有的target对象。为了保证线程安全,需要把这个替换方法设为synchronized方法,如代码清单3-34所示。

代码清单3-34 HotSwappableTargetSource的swap方法

        public synchronized Object swap(Object newTarget) throws IllegalArgumentException {
            Assert.notNull(newTarget, "Target object must not be null");
            Object old = this.target;
            this.target = newTarget;
            return old;
            }
            public synchronized Object getTarget() {
                return this.target;
        }

这个target是怎样在AOP中起作用的呢?了解一下对getTarget的调用就很清楚了,HotSwappableTargetSource只是对真正的target做了一个简单的封装,以提供热交换的能力,并没有其他特别之处。对getTarget的方法调用关系,如图3-21所示。

图3-21 AOP对getTarget的调用

以JdkDynamicAopProxy的实现为例,可以看到在AOP对Proxy代理对象进行invoke方法调用的时候,会通过getTarget调用取得真正的目标对象,如果已经调用过swap方法完成目标对象的热交换,那么交给AOP的已经是交换后的目标对象了,如代码清单3-35所示。具体来说,在invoke方法中,代理对象是在AopProxy代理对象的拦截器起作用之前,通过targetSource.getTarget()的调用来取得的,而这个代理对象是否被更换过,是由对swap方法的调用来负责的。因此,在invoke方法中,使用了什么样的代理对象,都不会对拦截器的行为做任何的改变。

代码清单3-35 invoke获取目标对象

        target = targetSource.getTarget();
        if (target != null) {
            targetClass = target.getClass();
        }
                    // 这里获得定义好的拦截器链
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice
        (method, targetClass);
        // 如果没有设定拦截器,那么就直接调用target的对应方法
        if (chain.isEmpty()) {
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
        }
        else {
            // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法
            //通过构造一个ReflectiveMethodInvocation来实现
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args,
            targetClass, chain);
            //沿着拦截器链,对Joinpoint连接器进行调用
            retVal = invocation.proceed();
        }
                    if (retVal != null && retVal == target && method.getReturnType().
                    isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            retVal = proxy;
        }
        return retVal;

通过getTarget方法,完成了HotSwappableTargetSource与AOP的集成。这个热交换功能为AOP的使用提供了更多便利,对构建应用的基础服务是非常有帮助的,比如可以在运行时支持需要改变的对象进行重新配置。对于其他AOP的高级特性,有兴趣的读者可以结合自己的需要进行分析。