spring AOP (三) 建立AopProxy代理对象

  在Spring的AOP模块中,一个主要的部分是代理对象的生成,而对于Spring应用,可以看到,是通过配置和调用Spring的ProxyFactoryBean来完成这个任务的。在

ProxyFactoryBean中,封装了主要代理对象的生成过程。在这个生成过程中,可以使用JDK的Proxy和CGLIB两种方式。

  类继承关系如下

  在这个类继承关系中,可以看到完成AOP应用的类,比如AspectJProxyFactory  ProxyFactory和ProxyFactoryBean,AspectJProxyFactory起到集成Spring和AspectJ

的作用,对于使用Spring AOP的应用, ProxyFactoryBean和ProxyFactory都提供类AOP的封装,只是使用ProxyFactoryBean,可以在IoC容器中完成声明式配置,而使用

ProxyFactory,则需要编程式地使用Spring AOP的功能

 

配置ProxyFactoryBean

   我们从ProxyFactoryBean的实现作为例子和实现的基本线索进行分析。需要如下配置步骤来使用ProxyFactoryBean

   1)定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义

   2)定义ProxyFactoryBean,把它作为另一个Bean来定义,它是封装AOP功能的主要类。在配置ProxyFactoryBean时,需要设置与AOP实现相关的重要属性,比如

proxyInterface  interceptoName和target等。

   3)定义target属性,作为target属性注入的Bean,是需要用AOP通知器中的切面应用来增强的对象

 1 <bean id="test" class="org.springframework.tests.sample.beans.TestBean">
 2         <property name="name"><value>custom</value></property>
 3         <property name="age"><value>666</value></property>
 4     </bean>
 5 
 6     <bean id="debugInterceptor" class="org.springframework.tests.aop.interceptor.NopInterceptor"/>
 7 
 8     <bean id="test1" class="org.springframework.aop.framework.ProxyFactoryBean">
 9         <property name="interfaces"><value>org.springframework.tests.sample.beans.ITestBean</value></property>
10         <property name="target"><ref local="test"/></property>
11         <property name="interceptorNames"><value>debugInterceptor</value></property>
12     </bean>

 

ProxyFactoryBean生成AopProxy代理对象

  这个ProxyFactoryBean是一个FactoryBean,是以getObject()方法作为入口完成的

 

 

  为Proxy代理对象配置Advisor链是在initializeAdvisorChain方法中完成的

 1     private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
 2         if (this.advisorChainInitialized) {
 3             return;
 4         }
 5 
 6         if (!ObjectUtils.isEmpty(this.interceptorNames)) {
 7             if (this.beanFactory == null) {
 8                 throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
 9                         "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
10             }
11 
12             // Globals can't be last unless we specified a targetSource using the property...
13             if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
14                     this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
15                 throw new AopConfigException("Target required after globals");
16             }
17 
18             // Materialize interceptor chain from bean names.
19             for (String name : this.interceptorNames) {
20                 if (logger.isTraceEnabled()) {
21                     logger.trace("Configuring advisor or advice '" + name + "'");
22                 }
23 
24                 if (name.endsWith(GLOBAL_SUFFIX)) {
25                     if (!(this.beanFactory instanceof ListableBeanFactory)) {
26                         throw new AopConfigException(
27                                 "Can only use global advisors or interceptors with a ListableBeanFactory");
28                     }
29                     addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
30                             name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
31                 }
32 
33                 else {
34                     // If we get here, we need to add a named interceptor.
35                     // We must check if it's a singleton or prototype.
36                     Object advice;
37                     if (this.singleton || this.beanFactory.isSingleton(name)) {
38                         // Add the real Advisor/Advice to the chain.
39                         advice = this.beanFactory.getBean(name);
40                     }
41                     else {
42                         // It's a prototype Advice or Advisor: replace with a prototype.
43                         // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
44                         advice = new PrototypePlaceholderAdvisor(name);
45                     }
46                     addAdvisorOnChainCreation(advice, name);
47                 }
48             }
49         }
50 
51         this.advisorChainInitialized = true;
52     }

所有的Advisor 都保存到基类AdvisedSupport 属性advisors和advisorArray中

在JdkDynamicAopProxy的invoke方法中片段

 1             // Get the interception chain for this method.
 2             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 3 
 4             // Check whether we have any advice. If we don't, we can fallback on direct
 5             // reflective invocation of the target, and avoid creating a MethodInvocation.
 6             if (chain.isEmpty()) {
 7                 // We can skip creating a MethodInvocation: just invoke the target directly
 8                 // Note that the final invoker must be an InvokerInterceptor so we know it does
 9                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
10                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
11             }
12             else {
13                 // We need to create a method invocation...
14                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
15                 // Proceed to the joinpoint through the interceptor chain.
16                 retVal = invocation.proceed();
17             }

通过类型是AdvisedSupport的advised获取到代理链chain,然后通过ReflectiveMethodInvocation循环增强调用,cglib类似

 

aop配置自动代理

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4         xmlns:aop="http://www.springframework.org/schema/aop"
 5         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
 6                 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
 7 
 8     <aop:config proxy-target-class="true" expose-proxy="true">
 9         <aop:pointcut id="getNameCalls" expression="execution(* getName(..)) and within(*..ITestBean+)"/>
10         <aop:advisor id="getAgeAdvisor" pointcut="execution(* *..ITestBean.getAge(..))" advice-ref="getAgeCounter"/>
11         <aop:advisor id="getNameAdvisor" pointcut-ref="getNameCalls" advice-ref="getNameCounter"/>
12 
13         <aop:aspect id="countAgeCalls" ref="countingAdvice">
14             <aop:pointcut id="setCalls" expression="execution(* *..ITestBean.set*(..))"/>
15             <aop:before pointcut="execution(* *..ITestBean.set*(..))" method="myBeforeAdvice"/>
16             <aop:after pointcut-ref="setCalls" method="myAfterAdvice"/>
17             <aop:around pointcut-ref="setCalls" method="myAroundAdvice"/>
18         </aop:aspect>
19 
20     </aop:config>
21 
22     <bean id="getNameCounter" class="org.springframework.tests.aop.advice.CountingBeforeAdvice"/>
23 
24     <bean id="getAgeCounter" class="org.springframework.tests.aop.advice.CountingBeforeAdvice"/>
25 
26     <bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
27 
28     <bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
29 
30 </beans>

自动代理的话,处理过程如下

在spring-framework-3.2.18 源码中

org.springframework.aop.config.AopNamespaceHandlerProxyTargetClassTests 自行debug

 

  1)哪么什么时候注册的AspectJAwareAdvisorAutoProxyCreator?,在BeanFactory读取xml文件  loadBeanDefinition时,会有一个

key为“org.springframework.aop.config.internalAutoProxyCreator” ,value为 AspectJAwareAdvisorAutoProxyCreator的 BeanDefinition

至于为什么会有这个beanDefinition,查看如下调用过程

 

 

2)在AbstractApplicationContext中registerBeanPostProcessors方法,会根据beanDefinitionMap中是否有类型

是BeanPostProcessor的beanDefinition,进行实例化,并且加到beanPostProcessor链表中,查看如下调用栈

3)在BeanFactory初始化时会注册BeanPostProcessor子类 AspectJAwareAdvisorAutoProxyCreator

processor在bean生成过程中会注入advisor

 

posted on 2018-10-10 01:04  持续在更新  阅读(310)  评论(0编辑  收藏  举报

导航