更新:2018/4/2 修改字体、添加引言。
0 引言
AOP是Aspect Oriented Programing的简称,面向切面编程。AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理、缓存、对象池管理以及日志记录。AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中。AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。
代理对象的方法 = 增强处理 + 被代理对象的方法
Spring AOP 则采用运行时生成 AOP 代理类,因此无需使用特定编译器进行处理。由于 Spring AOP 需要在每次运行时生成 AOP 代理,因此性能略差一 些。
AOP使用场景:AOP用来封装横切关注点,具体可以在下面的场景中使用:
Authentication 权限、Caching 缓存、Context passing 内容传递、Error handling 错误处理、Lazy loading 懒加载、Debugging 调试、logging, tracing, profiling and monitoring 记录跟踪 优化 校准、Performance optimization 性能优化、Persistence 持久化、Resource pooling 资源池、Synchronization 同步、Transactions 事务
1 建立AopProxy代理对象
1.1 配置ProxyFactoryBean
从这部分开始,我们进入到Spring AOP的实现部分,在分析Spring AOP的实现原理中,我们主要以ProxyFactoryBean的实现作为例子和实现的基本线索进行分析。很大一个原因是因为ProxyFactoryBean是在Spring IoC环境中,创建AOP应用的最底层方法,也是最灵活的方法,Spring通过它完成了对AOP使用的封装,以它的实现为入口逐层深入,是很好的一条帮助我们理解Spring AOP实现的学习路径。
在了解ProxyFactoryBean的实现之前,我们先简要地了解一下ProxyFactoryBean的配置和使用,在基于XML配置Spring的Bean的时候,往往需要一系列的配置步骤来使用ProxyFactoryBean和AOP,比如以下这些步骤:
1)定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义。很重要的一点,这个通知器的实现定义了需要对目标对象进行增强的切面行为,也就是Advice通知。
2)定义proxyFactoryBean,把它作为另一个Bean来定义,它是封装AOP功能的主要类。在配置ProxyFactoryBean时,需要设定与AOP实现相关的重要属性,比如ProxyInterface、interceptorNames和target等。从属性名称可以看出,interceptorNames属性的值往往设置为需要定义的通知器,因为这些通知器在ProxyFactoryBean的AOP配置下,是通过使用代理对象的拦截器机制起作用的。所以,这里依然沿用了拦截器这个名字,也算是旧瓶装新酒吧。
3)定义target属性,作为target属性注入的Bean,是需要用AOP通知器中的切面应用来增强的对象,也就是前面我们提到的base对象。
有了这些配置,就可以使用ProxyFactoryBean完成AOP的基本功能了。关于配置的例子,如代码清单3-10所示。与前面提到的配置步骤相对应,除了定义了ProxyFactoryBean的AOP封装,还定义了一个Advisor,取名为testAdvisor。作为ProxyFactory配置的一部分,还需要配置拦截的方法调用接口和目标对象。这些基本的配置,是使用ProxyFactoryBean实现AOP功能的重要组成,对于这些配置的实现和作用机制,也是我们后面重点分析的内容。
代码清单3-10 配置ProxyFactoryBean
- <bean id=“testAdvisor” class=“com.abc.TestAdvisor”/>
- <bean id=“testAOP” class=”org.springframework.aop.ProxyFactoryBean>
- <property name=“proxyInterfaces”><value>com.test.AbcInterface”
- </value></property>
- <property name=“target”>
- <bean class=“com.abc.TestTarget”/>
- </property>
- <property name=“interceptorNames”>
- <list><value> testAdvisor</value></list>
- </property>
- </bean>
掌握这些配置后,就可以具体看一看这些AOP是如何实现的。也就是说,切面应用是怎样通过ProxyFactoryBean对target对象起作用的。对于这个ProxyFactoryBean,我们先了解一下ProxyFactoryBean的类层次关系,如图3-8所示。在这个类层次关系中,可以看到用来完成AOP应用的类,比如AspectJProxyFactory、ProxyFactory和ProxyFactoryBean,它们都在同一个类的继承体系下,都是ProxyConfig、AdvisedSupport和ProxyCreatorSupport的子类。作为大家的共同基类,ProxyConfig可以看成是一个数据类,这个数据基类为像ProxyFactoryBean这样的子类提供了配置属性。在另一个基类AdvisedSupport的实现中,它封装了AOP中对通知和通知器的相关操作,这些操作对于不同的AOP的代理对象的生成都是一样的,但对于具体的AOP代理对象的创建,AdvisedSupport把它交给它的子类们去完成。ProxyCreatorSupport看成是其子类创建AOP代理对象的一个辅助类,通过继承以上提到的基类的功能实现,具体的AOP代理对象的生成,根据不同的需要分别由ProxyFactoryBean、AspectJProxyFactory和ProxyFactory来完成。对于需要使用AspectJ的AOP应用,AspectJProxyFactory起到集成Spring和AspectJ的作用;对于使用Spring AOP的应用,ProxyFactoryBean和ProxyFactoy都提供了AOP功能的封装,只是如果使用ProxyFactoryBean,可以在IoC容器中完成声明式配置,而使用ProxyFactory,则需要编程式的使用Spring AOP的功能;对于它们是如何封装实现AOP功能的,在本章后面的小节中给出详细的分析,在这里,通过这些类层次关系的了解,希望能先给读者留下一个大致的印象。
1.2 ProxyFactoryBean生成AopProxy
在Spring AOP的使用中,我们已经了解到,可以通过ProxyFactoryBean来配置目标对象和方面行为。这个ProxyFactoryBean是一个FactoryBean,对FactoryBean这种Spring应用中经常出现的Bean的工作形式,读者一定不会感到陌生,对于FactoryBean的工作原理,我们在结合IoC容器的实现原理分析中已经做过阐述。在ProxyFactoryBean中,通过interceptorNames属性来配置已经定义好的通知器Advisor。虽然这里的名字叫interceptNames,但值得注意的是,实际上却是供AOP应用配置通知器的地方。在ProxyFactoryBean中,需要为target目标对象生成Proxy代理对象,从而为AOP横切面的编织做好准备工作。
这些具体的代理对象生成工作,在以后的实现原理分析中,我们可以看到是通过JDK的Proxy或CGLIB来完成的。
在ProxyFactoryBean中,它的AOP实现需要依赖JDK或者CGLIB提供的Proxy特性。从FactoryBean中获取对象,是用getObject()方法作为入口完成的;让我们进入ProxyFactoryBean的实现中去,这个我们一点也不陌生的getObject方法,是FactoryBean需要实现的接口。对ProxyFactoryBean来说,把需要对target目标对象增加的增强处理,都通过getObject方法进行封装了,这些增强处理是为AOP功能的实现提供服务的。对于getObject的实现如代码清单3-11所示。getObject方法首先对通知器链进行初始化,通知器链封装了一系列的拦截器,这些拦截器都要从配置中读取,然后为代理对象的生成做好准备。在生成代理对象的时候,因为Spring中有sigleton类型和prototype类型这两种不同的Bean,所以这里对代理对象的生成需要做一个区分。
代码清单3-11 ProxyFactoryBean的getObject
- public Object getObject() throws BeansException {
- //这里初始化通知器链。
- initializeAdvisorChain();
- //这里对singleton和protype的类型进行区分,生成对应的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();
- }
- }
为Proxy代理对象配置Advisor链是在initializeAdvisorChain方法中完成的,如代码清单3-12所示。这个初始化过程有一个标志位advisorChainInitialized,这个标志用来表示通知器链是否已经初始化。如果已经初始化,那么这里就不会再初始化,而是直接返回。也就是说,这个初始化的工作,发生在应用第一次通过ProxyFactoryBean去获取代理对象的时候。在完成这个初始化之后,接着会读取配置中出现的所有通知器,这个取得通知器的过程也比较简单,把通知器的名字交给容器的getBean方法就可以了,这是通过对IoC容器实现的一个回调来完成的。然后把从IoC容器中取得的通知器加入到拦截器链中,这个动作是由addAdvisorOn-ChainCreation方法来实现的。
代码清单3-12 对Advisor配置链的初始化
- 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.
- 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中的配置,为生成代理对象做好必要的准备,比如设置代理的方法调用接口等。对于在getSingletonInstance()方法中代理对象的生成过程,如代码清单3-13所示。
代码清单3-13 生成单件代理对象
- 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.
- Class targetClass =
- getTargetClass();
- if (targetClass == null) {
- throw new
- FactoryBeanNotInitializedException(“Cannot determine
- target class for proxy”);
- }
- // 这里设置代理对象的接口。
- setInterfaces(ClassUtils.getAllInterfacesForClass(targetClas
- s, this.proxyClassLoader));
- }
- // Initialize the shared singleton instance.
- super.setFrozen(this.freezeProxy);
- //
- 注意这里的方法会使用ProxyFactory来生成我们需要的Proxy。
- this.singletonInstance =
- getProxy(createAopProxy());
- }
- return this.singletonInstance;
- }
- //使用createAopProxy返回的AopProxy来得到代理对象。
- protected Object getProxy(AopProxy aopProxy) {
- return aopProxy.getProxy(this.proxyClassLoader);
- }
这里出现了AopProxy类型的对象,Spring使用这个AopProxy接口类把AOP代理对象的实现与框架的其他部分有效地分离开来。AopProxy是一个接口,它有两个子类实现,一个是Cglib2AopProxy,另一个是JdkDynamicProxy。顾名思义,对这两个AopProxy接口的子类实现,Spring分别使用CGLIB和JDK来生成需要的Proxy代理对象。
具体的代理对象的生成,是在ProxyFactoryBean的基类AdvisedSupport的实现中通过AopProxyFactory完成的,这个代理对象要么从JDK中生成,要么借助CGLIB获得。因为ProxyFactoryBean本身就是AdvisedSupport的子类,在ProxyFactoryBean中获得AopProxy是很方便的,具体的AopProxy生成过程,我们可以在ProxyCreatorSupport中看到。至于需要生成什么样的代理对象,信息都封装在AdvisedSupport里,这个对象也是生成AopProxy的方法的输入参数,这里设置为this本身,因为ProxyCreatorSupport本身就是AdvisedSupport的子类。在ProxyCreatorSupport中生成代理对象的入口实现,如代码清单3-14所示。
代码清单3-14 ProxyCreatorSupport生成AopProxy对象
- protected final synchronized AopProxy createAopProxy() {
- if (!this.active) {
- activate();
- }
- /**
- *通过AopProxyFactory取得AopProxy,
- 这个AopProxyFactory是在
- *初始化函数中定义的,使用的是DefaultAopProxyFactory。
- */
- return getAopProxyFactory().createAopProxy(this);
- }
这里使用了AopProxyFactory来创建AopProxy,AopProxyFactory使用的是DefaultAopProxyFactory。这个被使用的AopProxyFactory,作为AopProxy的创建工厂对象,是在ProxyFactoryBean的基类ProxyCreatorSupport中被创建的。在创建AopProxyFactory的时候,它被设置为DefaultAopProxyFactory。很显然,Spring给出了这个默认的AopProxyFactory工厂的实现。有了这个AopProxyFactory对象以后,问题就转换为:在DefaultAopProxyFactory中AopProxy是怎样生成的问题了。
关于AopProxy代理对象的生成,需要考虑使用哪种生成方式,如果目标对象是接口类,那么适合使用JDK来生成代理对象,否则Spring会使用CGLIB来生成目标对象的代理对象。为了满足不同的代理对象生成的要求,DefaultAopProxyFactory作为AopProxy对象的生产工厂,可以根据不同的需要生成这两种AopProxy对象。对于AopProxy对象的生产过程,在DefaultAopProxyFactory中创建AopProxy的代码中可以清楚地看到,但这是一个比较高层次的AopProxy代理对象的生成过程,如代码清单3-15所示。所谓高层次,是指在DefaultAopProxyFactory创建AopProxy的过程中,对不同的AopProxy代理对象的生成,所涉及的生成策略和场景做了相应的设计,但是对于具体的AopProxy代理对象的生成,最终并没有由这个DefaultAopProxyFactory来完成,比如对JDK和CGLIB这些具体的技术的使用,对具体的实现层次的代理对象的生成,是由Spring封装的JdkDynamicAopProxy和CglibProxyFactory类来完成的。
在AopProxy代理对象的生成过程中,首先要从AdvisedSupport对象中取得配置的目标对象,这个目标对象是实现AOP功能所必需的,道理很简单,AOP完成的是切面应用对目标对象的增强,皮之不存,毛将焉附,这个目标对象可以看做是”皮”,而AOP切面增强就是依附于这块皮上的”毛发”。如果这里发现没有配置目标对象的话,会直接抛出异常,提醒AOP应用,需要提供正确的目标对象的配置。在对目标对象配置的检查完成以后,需要根据配置的情况来决定使用什么方式来创建AopProxy代理对象。一般而言,默认的方式是使用JDK来产生AopProxy代理对象,但是如果遇到配置的目标对象不是接口类的实现的时候,会使用CGLIB来产生AopProxy代理对象;在使用CGLIB来产生AopProxy代理对象的时候,因为CGLIB是一个第三方的类库,本身不在JDK的基本类库中,所以需要在CLASSPATH路径中正确地配置,以便能够加载和使用。在Spring中,使用JDK和CGLIB来生成AopProxy代理对象的工作,是由JdkDynamicAopProxy和CglibProxyFactory来完成的。对于详细的代理对象的生成过程,在下面的小节中,将逐个进行详细的分析。
代码清单3-15 在DefaultAopProxyFactory中创建AopProxy
- public AopProxy createAopProxy(AdvisedSupport config) throws
- AopConfigException {
- if (config.isOptimize() ||
- config.isProxyTargetClass() || hasNoUserSupplied
- ProxyInterfaces(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是接口类,使用JDK来生成Proxy。
- if (targetClass.isInterface()) {
- return new
- JdkDynamicAopProxy(config);
- }
- if (!cglibAvailable) {
- throw new AopConfigException(
- “Cannot proxy target
- class because CGLIB2 is not available. ” +
- “Add CGLIB to the
- class path or specify proxy interfaces.”);
- }
- //如果不是接口类要生成proxy,那么使用cglib来生成。
- return
- CglibProxyFactory.createCglibProxy(config);
- }
- else {
- return new JdkDynamicAopProxy(config);
- }
- }
1.3 JDK生成AopProxy代理对象
我们都知道对于AopProxy代理对象,可以由JDK或CGLIB来生成,而JdkDynamicAopProxy和Cglib2AopProxy实现的都是AopProxy接口,它们的层次关系如图3-9所示。
我们先看看在AopProxy接口实现中,JdkDynamicAopProxy是怎样完成AopProxy代理对象生成工作的。这个代理对象的生成过程如代码清单3-16所示。在JdkDynamicAopProxy中,使用了JDK的Proxy类来生成代理对象,在生成Proxy对象之前,首先需要从advised对象中取得代理对象的代理接口配置,然后调用Proxy的newProxyInstance方法,最终得到对应的Proxy代理对象;
在生成代理对象的时候,需要指明三个参数,分别是类装载器、代理接口和Proxy回调方法所在的对象,
这个对象需要实现InvocationHandler接口;InvocationHandler接口定义了invoke方法,提供代理对象的回调入口;对于JdkDynamicAopProxy,它本身实现了InvocationHandler接口和invoke方法,这个invoke方法是Proxy代理对象的回调方法,所以可以使用this来把JdkDynamicAopProxy指派给Proxy对象;也就是说JdkDynamicAopProxy对象本身,在Proxy代理的接口方法被调用时,会促发invoke方法的回调。在这个回调方法里,完成了AOP编织实现的封装。在这里,我们先重点关注AopProxy代理对象的生成,Proxy代理对象的invoke实现,将是我们后面详细分析AOP实现原理的重要部分。
代码清单3-16 JdkDynamicAopProxy生成Proxy代理对象
- 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.4 CGLIB生成AopProxy代理对象
在AopProxy接口实现中,可以看到使用CGLIB来生成Proxy代理对象,这个Proxy代理对象的生成,可以在Cglib2AopProxy的代码实现中看到,同样是在AopProxy的接口方法getProxy的实现完成的,如代码清单3-17所示。可以看到具体对CGLIB的使用,比如对Enhancer对象的配置,以及通过Enhancer对象生成代理对象的过程。在这个生成代理对象的过程中,需要注意的是对Enhancer对象callback回调的设置,正是通过这些callback回调,封装了Spring AOP的实现,就像我们在前面看到的JDK的Proxy对象的invoke回调方法一样;
在Enhancer的callback回调设置中,实际上是通过设置DynamicAdvisedInterceptor拦截器来完成AOP功能的,
如果读者感兴趣的话,可以在getCallbacks方法实现中看到回调DynamicAdvisedInterceptor的设置:
- Callback aopInterceptor =
- new DynamicAdvisedInterceptor(this.advised);
对于这个DynamicAdvisedInterceptor中的回调实现,我们将在后面详细地进行分析。
代码清单3-17 Cglib2AopProxy生成AopProxy代理对象
- public Object getProxy(ClassLoader classLoader) {
- if (logger.isDebugEnabled()) {
- logger.debug(“Creating CGLIB2 proxy: target
- source is ” + this.advised.
- getTargetSource());
- }
- //从advised中取得在IoC容器中配置的target对象。
- try {
- Class rootClass =
- this.advised.getTargetClass();
- Assert.state(rootClass != null, “Target
- class must be available for
- creating a CGLIB proxy”);
- Class proxySuperClass = rootClass;
- if (AopUtils.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…
- //
- 创建并配置CGLIB的Enhancer,这个Enhancer对象是CGLIB的主要操作
- 类。
- Enhancer enhancer = createEnhancer();
- if (classLoader != null) {
- enhancer.setClassLoader(classLoader);
- if (classLoader instanceof
- SmartClassLoader &&
- ((SmartClassLoader)
- classLoader).isClassReloadable
- (proxySuperClass)) {
- enhancer.setUseCache(false);
- }
- }
- /**
- *设置Enhancer对象,包括设置代理接口,回调方法,回调方法来自
- *advised的IoC配置,比如使用AOP的DynamicAdvisedInterceptor拦
- 截器。
- */
- enhancer.setSuperclass(proxySuperClass);
- enhancer.setStrategy(new
- UndeclaredThrowableStrategy(UndeclaredThrowable
- Exception.class));
- enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfac
- es(this.advised));
- enhancer.setInterceptDuringConstruction(false);
- Callback[] callbacks =
- getCallbacks(rootClass);
- enhancer.setCallbacks(callbacks);
- enhancer.setCallbackFilter(new
- ProxyCallbackFilter(
- this.advised.getConfigurationOnlyCopy(),
- this.fixedInterceptorMap,
- this.fixedInterceptorOffset));
- Class[] types = new Class[callbacks.length];
- for (int x = 0; x < types.length; x++) {
- types[x] = callbacks[x].getClass();
- }
- enhancer.setCallbackTypes(types);
- // 通过Enhancer生成代理对象。
- 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);
- }
- }
这样,通过使用AopProxy对象封装target目标对象之后,通过ProxyFactoryBean的getObject方法得到的对象就不是一个普通的Java对象了,而是一个AopProxy代理对象。在ProxyFactoryBean中配置的target目标对象,这个时候已经不会直接暴露给应用,而是作为AOP实现的一部分。对target目标对象的方法调用会首先被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。例如,对于JDK的AopProxy代理对象,使用的是InvocationHandler的invoke回调入口;而对于CGLIB的AopProxy代理对象,使用的是设置好的callback回调,这是由对CGLIB的使用来决定的;在这些callback回调中,对于AOP实现,是通过DynamicAdvisedInterceptor来完成的,而DynamicAdvisedInterceptor的回调入口是intercept方法。通过这一系列的准备,已经为实现AOP的横切机制奠定了基础,在这个基础上,AOP的Advisor已经可以通过AopProxy代理对象的拦截机制,对需要它进行增强的target目标对象发挥切面的强大威力了。
可以把AOP的实现部分看成由基础设施准备和AOP运行辅助这两个部分组成。这里的AopProxy代理对象的生成,可以看成是一个静态的AOP基础设施的建立过程。通过这个准备过程把代理对象、拦截器这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。对于应用触发的AOP应用,会涉及AOP框架的运行和对AOP基础设施的使用。这些动态的运行部分,是从我们前面提到的拦截器回调入口开始的,这些拦截器调用的实现原理和AopProxy代理对象生成一样,也是AOP实现的重要组成部分,同时也是我们下面要重点分析的内容,让我们继续深入到AopProxy代理对象的回调实现中去看一看,慢慢地揭开Spring AOP实现的另一层神秘的面纱。
2.小结
在本章中,我们对最基本Spring AOP的实现方式进行了解析。具体地说,通过使用ProxyFactoryBean/ProxyFactory的实现原理作为例子,对Spring AOP的基本实现和工作原理进行了一些梳理和分析。ProxyFactoryBean是在IoC环境中创建代理的一个很灵活的方法,与其他方法相比,虽然有些繁琐,但却并不妨碍我们从ProxyFactoryBean入手,去了解AOP在Spring中的基本实现。
在Spring AOP的基本实现中,可以了解Spring是如何得到AopProxy代理对象的,以及它是如何利用AopProxy代理对象来对拦截器进行处理的。Proxy代理对象的使用,在Spring AOP的实现过程中是非常重要的一个部分,Spring AOP充分利用了像Java的Proxy、反射技术以及第三方字节码技术实现CGLIB这些技术方案,通过这些技术完成了AOP需要的AopProxy代理对象的生成。回顾整个通过ProxyFactoryBean实现AOP的过程我们可以看到,在它的实现中,首先需要对目标对象进行正确的配置,以及对拦截器的正确配置,以便AopProxy代理对象得以顺利产生;这些配置既可以通过配置ProxyFactoryBean的属性来完成,也可以通过编程式的使用ProxyFactory来实现。这两种AOP的使用方式,只是在表面配置的方式上不同而已,对于内在的AOP实现原理它们是一样的。在生成AopProxy代理对象的时候,Spring AOP设计了专门的AopProxyFactory作为AopProxy代理对象的生产工厂,由它来负责产生相应的AopProxy代理对象,在使用ProxyFactoryBean来得到AopProxy代理对象的时候,它默认地使用的AopProxy代理对象的生产工厂是DefaultAopProxyFactory对象。这个对象是一个在AopProxy生产过程中比较重要的类,它定义了AopProxy代理对象的生成策略,从而决定使用哪一种AopProxy代理对象的生成技术,是使用JDK的Proxy类还是使用CGLIB来完成生产任务。而对于最终的AopProxy代理对象的产生,则是交给JdkDynamicAopProxy和Cglib2AopProxy这两个具体的工厂来完成AopProxy代理对象的生产的,它们使用了不同的生产技术,一种使用的是JDK的Proxy技术,它使用InvocationHandler对象的invoke完成回调,而另一种则是使用CGLIB的技术来生成AopProxy代理对象。
在得到AopProxy代理对象后,在代理的接口方法被调用执行的时候,也就是当AopProxy暴露代理的方法被调用的时候,前面定义的Proxy机制就起作用了。当Proxy对象暴露的方法被调用时,并不是直接地运行目标对象的调用方法,而是会根据Proxy的定义,改变了原有的目标对象方法调用的运行轨迹。这种改变体现在,首先会触发对这些方法调用进行拦截,这些拦截为对目标调用的功能增强提供了工作空间;拦截过程在JDK的Proxy代理对象中,是通过invoke方法来完成的,这个invoke方法是虚拟机触发的一个回调。而在CGLIB的Proxy代理对象中,拦截是由设置好的回调callback方法来完成的。有了这些拦截器的拦截作用,才会有AOP切面增强大显身手的舞台。
在ProxyFactoryBean的回调中,首先会根据配置来对拦截器是否与当前的调用方法相匹配来进行判断。如果当前的调用方法与配置的拦截器相匹配,那么相应的拦截器就会开始发挥作用,这个过程是一个遍历的过程,它会遍历在Proxy代理对象中设置的拦截器链中的所有拦截器。经过这个过程后,在代理对象中定义好的拦截器链里的拦截器会被逐一调用,直到整个拦截器的调用完成为止。在对拦截器的调用完成以后,才是我们最后看到的对目标对象(target)的方法调用。这样,一个普通的Java对象的功能就得到了增强,这种增强和现有的目标对象的设计是正交解耦的,这也是AOP需要达到的一个目标。
在拦截器的调用过程中,实际上已经封装了Spring对AOP的实现,比如对各种通知器的增强织入功能。尽管我们在使用Spring AOP的时候,看到的是一些advice的使用,但实际上这些AOP应用中接触到的这些advice通知是不能直接对目标对象完成增强的,为了完成AOP应用需要的对目标对象的增强,Spring AOP做了许多工作。这些工作包括,对应于每种advice通知,Spring设计了对应的AdviceAdapter通知适配器,正是这些AdviceAdapter通知适配器,实现了advice通知对目标对象的不同的增强方式。对于这些AdviceAdapter通知适配器,在AopProxy代理对象的回调方法中,需要有一个注册机制,它们才能发挥作用。完成这个注册过程之后,实际上在拦截器链中运行的拦截器,已经是经过这些AdviceAdapter适配过的拦截器了。有了这些拦截器,再去结合AopProxy代理对象的拦截回调机制,才能够让advice通知对目标对象的增强作用实实在在地发生。谁知盘中餐,粒粒皆辛苦,在软件开发的世界里,真是没有什么免费午餐。看起来简洁易用的AOP,和IoC容器的实现一样,背后同样蕴含着许多艰苦的努力。
熟悉AOP使用的读者还知道,除了提供AOP的一些基本功能之外,Spring还提供了许多其他高级特性让用户更加方便地使用AOP。对于这些高级特性,在本章中,我们选取了HotSwappableTargetSource来对它的实现原理进行分析,一叶知秋,一管窥豹,希望能够在这里为那些对AOP其他特性的实现感兴趣的读者打开一扇窗。
在本章中,我们提到了Proxy、反射等Java虚拟机特性的使用,CGLIB的使用以及在它们建立的Proxy对象的基础上,对拦截器特性的灵活运用,这些特性都是我们掌握本章内容的背景知识和重要基础。同时,不妨可以反过来看,通过了解本章中AOP的实现原理,也为我们使用这些Java虚拟机的特性以及CGLIB的技术,提供了生动而精彩的应用案例。在AOP的实现中,还有一个值得注意的地方就是,在ProxyFactoryBean得到advisor配置的实现过程中,是通过回调IoC容器的getBean方法来完成的,这个处理既简洁又巧妙,是灵活使用IoC容器功能的一个非常好的实例。以上这些,都是在本章中,除了Spring AOP实现原理本身之外,非常值得我们学习和研究的地方。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/13110.html