3.2 Spring AOP的设计与实现
3.2.1 JVM的动态代理特性
前面已经介绍了横切关注点的一些概念,以及它们在Spring中的具体设计和实现。具体来说,在Spring AOP实现中,使用的核心技术是动态代理,而这种动态代理实际上是JDK的一个特性(在JDK 1.3以上的版本里,实现了动态代理模式)。通过JDK的动态代理特性,可以为任意Java对象创建代理对象,对于具体使用来说,这个特性是通过Java Reflection API来完成的。在了解具体的Java Reflection之前,先简要地复习一下Proxy模式,其静态类图如图3-9所示。
在图3-9中,可以看到有一个RealSubject,这个对象是目标对象,而在代理模式的设计中,会设计一个接口和目标对象一致的代理对象Proxy,它们都实现了接口Subject的request方法。在这种情况下,对目标对象的request的调用,往往就被代理对象“浑水摸鱼”给拦截了,通过这种拦截,为目标对象的方法操作做了铺垫,所以称之为代理模式。了解了如图3-10所示的调用关系,就可以清楚地了解这里的过程。
在Proxy的调用过程中,如果客户(Client)调用Proxy的request方法,会在调用目标对象的request方法的前后调用一系列的处理,而这一系列的处理相对于目标对象来说是透明的,目标对象对这些处理可以毫不知情,这就是Proxy模式。
通过前面的介绍可以知道, JDK中已经实现了这个Proxy模式,在基于Java虚拟机设计应用程序时,只需要直接使用这个特性就可以了。具体来说,可以在Java的reflection包中看到Proxy对象,这个对象生成后,所起的作用就类似于Proxy模式中的Proxy对象。在使用时,还需要为代理对象(Proxy)设计一个回调方法,这个回调方法起到的作用是,在其中加入了作为代理需要额外处理的动作,或者说,在这个方法中,所谓额外动作,可以参考Proxy模式中的preOperation()和postOperation()方法。这个回调方法,如果在JDK中实现,需要实现下面所示的InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
在这个接口方法中,只声明了一个invoke方法,这个invoke方法的第一个参数是代理对象实例,第二个参数是Method方法对象,代表的是当前Proxy被调用的方法,最后一个参数是被调用的方法中的参数。通过这些信息,在invoke方法实现中,已经可以了解Proxy对象的调用背景了。至于怎样让invoke方法和Proxy挂上钩,熟悉Proxy用法的读者都知道,只要在实现通过调用Proxy.newIntance方法生成具体Proxy对象时把InvocationHandler设置到参数里面就可以了,剩下的由Java虚拟机来完成。
3.2.2 Spring AOP的设计分析
大家都知道,AOP模块是Spring的核心模块,虽然在Java社区里AspectJ是最完整的AOP框架,但Spring AOP也提供了另外一种实现,这种实现并不是AspectJ的竞争者,相反,Spring AOP还将AspectJ集成了进来,为IoC容器和Spring应用开发提供了一个一致性的AOP解决方案。
Spring AOP的核心技术是上一小节介绍的JDK动态代理技术。以动态代理技术为基础,设计出了一系列AOP的横切实现,比如前置通知、返回通知、异常通知等。同时,Spring AOP还提供了一系列的Pointcut来匹配切入点,可以使用现有的切入点来设计横切面,也可以扩展相关的Pointcut方法来实现切入需求。
在Spring AOP中,虽然对于AOP的使用者来说,只需要配置相关的Bean定义即可,但仔细分析Spring AOP的内部设计可以看到,为了让AOP起作用,需要完成一系列过程,比如,需要为目标对象建立代理对象,这个代理对象可以通过使用JDK的Proxy来完成,也可以通过第三方的类生成器cglib来完成。然后,还需要启动代理对象的拦截器来完成各种横切面的织入,这一系列的织入设计是通过一系列Adapter来实现的。通过一系列Adapter的设计,可以把AOP的横切面设计和Proxy模式有机地结合起来,从而实现在AOP中定义好的各种织入方式。具体的设计实现可以参考后面的内容,这里只是简要介绍一下。
3.2.3 Spring AOP的应用场景
Spring AOP为IoC的使用提供了更多的便利,一方面,应用可以直接使用AOP的功能,设计应用的横切关注点,把跨越应用程序多个模块的功能抽象出来,并通过简单的AOP的使用,灵活地编制到模块中,比如可以通过AOP实现应用程序中的日志功能。另一方面,在Spring内部,一些支持模块也是通过Spring AOP来实现的,比如后面将要详细介绍的事务处理。从这两个角度就已经可以看到Spring AOP的核心地位了。下面以ProxyFactoryBean的实现为例,和大家一起来了解Spring AOP的具体设计和实现。