zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    寒假学习记录07
    寒假学习记录06
    寒假学习记录05
    寒假学习记录04
    寒假学习记录03
    寒假学习记录02
    寒假学习记录01
    河北省重大技术需求征集系统(13)
    学习进度(4)
    学习进度(3)
  • 原文地址:https://www.cnblogs.com/toUpdating/p/9764064.html
Copyright © 2011-2022 走看看