基於Schema配置切面

    使用基於Schema的切面定義後,切點、加強類型的註解信息從切面類中剝離出來,原來的切面類也就蛻變爲真正意義上的POJO了。

一、一個簡單切面的配置java

基於Schema配置的切面示例:
<?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-3.0.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">
            <aop:before pointcut="target(com.yyq.schema.NaiveWaiter) and execution(* greetTo(..))"
                        method="preGreeting"/>
        </aop:aspect>
    </aop:config>
    <bean id="adviceMethods" class="com.yyq.schema.AdviceMethods"/>
    <bean id="naiveWaiter" class="com.yyq.schema.NaiveWaiter"/>
    <bean id="naughtyWaiter" class="com.yyq.schema.NaughtyWaiter"/>
</beans>

  使用一個<aop:aspect>元素標籤訂義切面,其內部能夠定義多個加強。在<aop:config>元素中能夠定義多個切面。經過<aop:before>聲明瞭一個前置加強,並經過pointcut屬性定義切點表達式,切點表達式的語法和@AspectJ中所用的語法徹底相同,因爲&&在XML中使用不便,因此通常用and操做符代替。經過method屬性指定加強的方法,該方法應該是adviceMethods Bean中的方法。spring

 
加強方法所在的類:
package com.baobaotao.schema;
import org.aspectj.lang.ProceedingJoinPoint;

public class AdviceMethods {
    public void preGreeting(String name) {
        System.out.println("--how are you!--");
        System.out.println(name);
    }
    //後置加強對應方法
    public void afterReturning(int retVal){
       System.out.println("----afterReturning()----");
       System.out.println("returnValue:"+retVal);
       System.out.println("----afterReturning()----");
    }
    //環繞加強對應方法
    public void aroundMethod(ProceedingJoinPoint pjp){
       System.out.println("----aroundMethod()----");
       System.out.println("args[0]:"+pjp.getArgs()[0]);
       System.out.println("----aroundMethod()----");
    }
    //拋出異常加強
    public void afterThrowingMethod(IllegalArgumentException iae){
       System.out.println("----afterThrowingMethod()----");
       System.out.println("exception msg:"+iae.getMessage());
       System.out.println("----afterThrowingMethod()----");
    }
    //final加強
    public void afterMethod(){
       System.out.println("----afterMethod()----");
    }
        
      //------------綁定鏈接點參數----------//
    public void bindParams(int num,String name){
       System.out.println("----bindParams()----");
       System.out.println("name:"+name);
       System.out.println("num:"+num);
       System.out.println("----bindParams()----");
    }
}

NaiveWaiter類:express

package com.yyq.schema;
public class NaiveWaiter implements Waiter {
    @Override
    public void greetTo(String name) {
        System.out.println("NaiveWaiter:greet to " + name + "...");
    }
    @Override
    public void serveTo(String name) {
        System.out.println("NaiveWaiter:serving to " + name + "...");
    }
    public void smile(String clientName,int times){
        System.out.println("NaiveWaiter:smile to  "+clientName+ times+"times...");
    }
}

NaughtyWaiter類:ide

package com.yyq.schema;
public class NaughtyWaiter implements Waiter {
    public void greetTo(String clientName) {
        System.out.println("NaughtyWaiter:greet to " + clientName + "...");
    }
    public void serveTo(String clientName) {
        System.out.println("NaughtyWaiter:serving " + clientName + "...");
    }
    public void joke(String clientName, int times) {
        System.out.println("NaughtyWaiter:play " + times + " jokes to " + clientName + "...");
    }
}

測試方法:函數

package com.yyq;
import com.yyq.schema.Waiter;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SchemaTest {
    @Test
    public void schemaTest(){
        String configPath = "com\\yyq\\schema\\beans.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
        Waiter naiveWaiter = (Waiter)ctx.getBean("naiveWaiter");
        Waiter naughtyWaiter = (Waiter)ctx.getBean("naughtyWaiter");
        naiveWaiter.greetTo("John");
        naughtyWaiter.greetTo("Tom");
    }
}
輸出結果:
---How are you !---
John
NaiveWaiter:greet to John...
NaughtyWaiter:greet to Tom...
 
二、配置命名切點
    經過pointcut屬性聲明的切點時匿名切點,它不能被其餘加強或其餘切面引用。Spring提供了命名切點的配置方式。
命名切點配置:
  <aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:pointcut id="greetToPointcut" expression="target(com.yyq.schema.NaiveWaiter) and execution(* greetTo(..))"/>
            <aop:before method="preGreeting" pointcut-ref="greetToPointcut"/>
        </aop:aspect>
    </aop:config>

  使用<aop:pointcut>定義了一個切點,並經過id屬性進行命名,經過pointcut-ref引用這個命名的切點。和<aop:before>同樣,除了引介加強外,其餘任意加強類型都擁有pointcut、pointcut-ref和method這3個屬性。post

    若是想要讓一個切點爲全部加強訪問,定義以下:
 <aop:config proxy-target-class="true">
        <aop:pointcut id="greetToPointcut2" expression="target(com.yyq.schema.NaiveWaiter) and execution(* greetTo(..))"/>
        <aop:aspect ref="adviceMethods">
            <aop:before method="preGreeting" pointcut-ref="greetToPointcut2"/>
        </aop:aspect>
        <aop:aspect ref="adviceMethods">
            <aop:after method="postGreeting" pointcut-ref="greetToPointcut2"/>
        </aop:aspect>
    </aop:config>

 

三、各類加強類型的配置測試

1)後置加強
<aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:after-returning method="afterReturning"
                                 pointcut="target(com.baobaotao.SmartSeller)" returning="retVal" />
        </aop:aspect>
    </aop:config>

2)環繞加強spa

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

3)拋出異常加強code

<aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:after-throwing method="afterThrowingMethod"
                                pointcut="target(com.baobaotao.SmartSeller) and execution(* checkBill(..))"
                                throwing="iae" />
        </aop:aspect>
    </aop:config>

4)Final加強xml

 <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
                    implement-interface="com.baobaotao.Seller"
                    default-impl="com.baobaotao.SmartSeller"
                    types-matching="com.baobaotao.Waiter+" />
        </aop:aspect>
    </aop:config>
 
四、綁定鏈接點信息
    基於Schema配置的加強方法綁定鏈接點信息和基於@AspectJ綁定鏈接點信息所使用的方式沒有區別。
    1)全部加強類型對應的方法第一個入參均可以聲明爲JoinPoint(環繞加強可聲明爲ProceedingJoinPoint)訪問鏈接點信息;
    2)<aop:after-returning>(後置加強)能夠經過returning屬性綁定鏈接點方法的返回值,<aop:after-throwing>(拋出異常加強)能夠經過throwing屬性綁定鏈接點方法所拋出的異常;
    3)全部加強類型均可以經過可綁定參數的切點函數綁定鏈接點方法的入參。
綁定鏈接點採納數到加強方法:
 <aop:config proxy-target-class="true">
        <aop:aspect ref="adviceMethods">
            <aop:before method="bindParams"
                        pointcut="target(com.yyq.schema.NaiveWaiter) and args(name,num,..)"/>
        </aop:aspect>
    </aop:config>

AdviceMethods綁定參數的加強方法:

//------------綁定鏈接點參數----------//
    public void bindParams(int num,String name){
        System.out.println("----bindParams()----");
        System.out.println("name:"+name);
        System.out.println("num:"+num);
        System.out.println("----bindParams()----");
    }
 
五、Advisor配置
    Advisor是Spring中切面概念的對應物,是切點和加強的複合體,不過僅包含一個切點和一個加強。在AspectJ中沒有對應的等價物,在aop Schema配置樣式中,能夠經過<aop:advisor>配置一個Advisor。經過advice-ref屬性引用基於接口定義的加強,經過pointcut定義切點表達式,或者經過pointcut-ref引用一個命名的切點。
  <aop:config proxy-target-class="true">
        <aop:advisor advice-ref="testAdvice"  pointcut="execution(* com..*.Waiter.greetTo(..))"/>
    </aop:config>
    <bean id="testAdvice" class="com.yyq.schema.TestBeforeAdvice"/>

 加強類:

package com.yyq.schema;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class TestBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        System.out.println("------TestBeforeAdvice------");
        System.out.println("clientName:"+args[0]);
        System.out.println("------TestBeforeAdvice------");
    }
}
相關文章
相關標籤/搜索