在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