《Spring》(十六)---- 基于Schema的AOP

要使用基于Schema的AOP,IoC容器的配置文件应该使用基于Schema的XML,同时在文件投中增加针对AOP的命名空间声明,如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    
    <!--相关bean定义-->
</bean>

新的基于Schema的AOP配置方式,针对Pointcut,Advisor以及Aspect等概念提供了独立的配置元素。所有这些配置元素都包含在统一的配置元素中,即<aop:config>, <aop:config> 只有一个属性proxy-target-class, 对应ProxyConfig中的proxyTargetClass属性,通过该属性可以控制使用基于类还是基于接口的动态代理。如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    
    <aop:config proxy-target-class="true">
        <!--其他aop概念元素定义-->
    </aop:config>    
    
    
</beans>

  <aop:config>内部可以有三个子元素,分别是<aop:pointcut>,<aop:advisor>和<aop:aspect>。它们三个必须按照顺序进行配置,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    
    <aop:config proxy-target-class="false">
        <aop:pointcut/>
                <aop:advisor/>
                <aop:aspect></aop:aspect>
    </aop:config>    
    
    
</beans>

  另外,可以在同一个配置文件中配置多个<aop:config>.

  <aop:config> 会根据元素内部对应的Pointcut,Advisor以及Aspect的子元素取得必要的织入信息,然后为容器内注册的bean进行自动代理。和使用AutoProxyCreator一样。但两者最好不要混用。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                              http://www.springframework.org/schema/beans/spring-beans.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    
    <aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods"> // 1
            <aop:before method="preGreeting" pointcut="target(com.ivy.NaiveWaiter) and execution(* greetTo(..))"/> // 2
        </aop:aspect>
    </aop:config>    
    
    <bean id="adviceMethods" class="com.ivy.schema.AdviceMethods"/> // 3
    <bean id="naiveWaiter" class="com.ivy.NaiveWaiter"/>
    <bean id="naughtWaiter" class="com.ivy.NaughtyWaiter"/>
</beans>

  

  使用一个<aop:aspect>元素标签定义切面,其内部可以定义多个增强。在<aop:config>元素中可以定义多个切面。在1处,切面引用了adviceMethods Bean, 该Bean是增强方法所在的类。通过<aop:before> 声明了一个前置增强,并通过pointcut属性定义切点表达式,method属性指定增强的方法,该方法应该是adviceMethods bean中的方法。

  <aop:config>拥有一个proxy-target-class属性,当设置为true时,表示其中声明的切面均使用CGLib动态代理技术;当设置为false时,使用JDK动态代理。一个配置文件可以同时定义多个<aop:config>,不同的<aop:config>可以采取不同的代理技术。

   

  1, 基于Schema的Aspect声明

<aop:config>
    <aop:aspect id="myAspect" ref="schemaBasedAspect" order="2">
         ...
    </aop:aspect>
</aop:config>

  2, 基于Schema的Pointcut声明

  基于Schema的Pointcut声明(<aop:pointcut〉)可以位于两个位置:一个位置是直接声明到<aop:config>下面,这样的Pointcut定义可以在其余的Advisor定义和Aspect定义中共享引用,另一个位置就是<aop:aspect>元素内部,这种Pointcut只能在其所声明的<aop:aspect〉内部引用,相当于修饰符是private。

<aop:config>
    <aop:aspect id="myAspect" ref="schemaBasedAspect" order="2">
         <aop:pointcut id="privatePointcut" expression="execution(public void *.doSth())" />
         ...
    </aop:aspect>
</aop:config>
<bean id="shemaBasedAspect" class="...SchemaBasedAspect"></bean>

  3, 基于Schema的Advice声明

  在基于Schema的AOP中的Advice声明也分为两部分,Advice定义和Advice到容器中的配置。

  

配置命名切点

  上例2处通过pointcut属性声明的切点是匿名切点,它不能被其他增强或其他切面使用,Spring提供了命名切点的配置方式:

<aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
          <aop:pointcut expression="target(com.ivy.NaiveWaiter)" id="greetToPointcut"/>
            <aop:before method="preGreeting" pointcut-ref="greetToPointcut"/>
        </aop:aspect>
    </aop:config>    

  <aop:pointcut>如果位于<aop:aspect>元素中,则命名切点只能被当前<aop:aspect>内定义的元素访问到,为了能被整个<aop:config>元素中定义的所有增强访问,则必须在<aop:config>下定义切点,且必须保证<aop:pointcut>在<aop:aspect>之前定义:

<aop:config proxy-target-class="true">
        <aop:pointcut expression="target(com.ivy.NaiveWaiter)" id="greetToPointcut"/>
        <aop:aspect ref="adviceMethods">
            <aop:before method="preGreeting" pointcut-ref="greetToPointcut"/>
        </aop:aspect>
        
        <aop:aspect ref="adviceMethods">
            <aop:after method="preGreeting" pointcut-ref="greetToPointcut"/>
        </aop:aspect>
    </aop:config>    

  各类增强配置

  1. 后置增强
    <aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:after-returning method="afterReturning" pointcut="target(com.ivy.Seller)" returning="retVal"/>
        </aop:aspect>
    </aop:config>    

增强对应方法:

public void afterReturning(int retVal) {
        // 增强方法,retVal和配置文件中的returning属性值相同
    }

如果增强不希望接收返回值,就把returning属性和增强方法的对应入参去掉即可。

  2. 环绕增强

<aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:around method="aroundMethod" pointcut="execution(* serveTo(..) and within(com.ivy.Waiter))"/>
        </aop:aspect>
    </aop:config>

  3. 抛出异常增强

<aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:after-throwing method="afterThrowingMethod" pointcut="target(com.ivy.Seller) and execution(* checkBill(..))" throwing="iae"/>
        </aop:aspect>
    </aop:config>
public void afterThrowingMethod(IllegalArgumentException iae) {
        
    }

  4. Final增强

<aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:after method="afterMethod" pointcut="execution(* com..*.Waiter.greetTo(..))"/>
        </aop:aspect>
    </aop:config>

  5. 引介增强

    <aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:declare-parents types-matching="com.ivy.Waiter+" implement-interface="com.ivy.Seller" default-impl="com.ivy.SmartSeller"/>
        </aop:aspect>
    </aop:config>

  <aop:declare-parents>通过implement-interfaces属性声明要实现的接口,通过default-impl属性指定默认的接口实现,然后通过type-matching属性以切点表达式语法指定哪些bean需要引介Seller接口的实现。

  

原文地址:https://www.cnblogs.com/IvySue/p/6589140.html