22_AOP_切面——靜態切面


【Spring AOP 如何定位連接點】

1.增強提供了連接點的方位信息:如織入到方法前面、后面等。

2.切點描述的是織入到哪些類的哪些方法上。

 

【切點】

  Spring通過org.springframework.aop.Pointcut接口描述切點,Pointcut由ClassFilter和MethodMatcher構成,通過ClassFilter定位到某些特定的,通過MethodMatcher定位到某些特定的方法。這樣,Pointcut就擁有了描述某些類的某些特定方法的能力。

可以看到:

  ClassFilter只定義了一個方法matches(Class clazz),其參數代表一個被檢測的類,該方法判別被檢測的類是否匹配過濾條件。

Spring提供了兩種方法匹配器:靜態方法匹配器和動態方法匹配器。

1.靜態方法匹配器

  僅對方法名簽名(包括方法名和入參類型及順序)進行匹配。靜態匹配僅判斷一次。

2.動態方法匹配器

  會在運行期間檢查方法入參的值。動態匹配因為每次調用方法的入參可能不一樣,導致每次調用方法都必須判斷,因此動態匹配對性能的影響較大。

  一般情況,動態匹配不常使用。

方法匹配器的類型由MethodMatcher接口的isRuntime()方法決定,返回false表示是靜態方法匹配器,返回true表示是動態方法匹配器。

 

【切點類型】

Spring提供了6種切點:

1.靜態方法切點:org.springframework.aop.support.StaticMethodMatcherPointcut

  StaticMethodMatcherPointcut是靜態方法切點的抽象基類,默認情況下匹配所有的類。StaticMethodMatcherPointcut有兩個重要的子類:NameMethodMatcherPointcut和AbstractRegexMethodPoint。前者提供簡單的字符串匹配方法簽名,后者使用正則表達式匹配方法簽名。

2.動態方法切點:org.springframework.aop.support.DynamicMethodMatcherPointcut

  DynamicMethodMatcherPointcut是動態方法切點的抽象基類,默認情況下它匹配所有的類。DynamicMethodMatcherPointcut已過時!!使用DefaultPointcutAdvisor和DynamicMethodPointcut動態方法匹配器代替。

3.注解切點

4.表達式切點

5.流程切點

6.復合切點

 

【切面類型】

Spring使用org.springframework.aop.Advisor接口表示切面的概念。

一個切面同時包含橫切代碼和連接點信息。切面分為三類:一般切面、切點切面、引介切面。

1.一般切面:Advisor

  它僅包含一個Advice,Advice包含了橫切代碼和連接點的信息,所以Advice本身就是一個簡單的切面,只不過它代表的是所有目標類的所有方法。由於這個橫切面過於寬泛,所以一把不會直接使用。

2.切點切面:PointcutAdvisor

  包含Advice和Pointcut兩個類。我們可以通過類、方法名以及方法方位等信息靈活定義切面的連接點,提供更具適用性的切面。

3.引介切面:IntroductionAdvisor

引介切面是對應引介增強的特殊的切面,它應用於類層面之上,所以引介切點適用ClassFilter進行定義。

 

【靜態普通方法名匹配切面 例子】

【奔馳車類:BenzCar.java】

package com.Higgin.part4;

public class BenzCar {
    public void driving(){
        System.out.println("奔馳車在行駛...");
    }
}

【寶馬車類:BMWCar.java】

package com.Higgin.part4;

public class BMWCar {
    public void driving(){
        System.out.println("寶馬車在行駛...");
    }
}

【汽車切面類:CarAdvisor.java】

package com.Higgin.part4;

import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
/**
 * 汽車類的切面CarAdvisor類
 * 實現接口:StaticMethodMatcherPointcutAdvisor
 *                     實現StaticMethodMatcherPointcutAdvisor接口唯一需要定義的是matches()方法,
 * 
 */
public class CarAdvisor extends StaticMethodMatcherPointcutAdvisor{

    /** * 切點方法 匹配 * 匹配規則:方法名為driving * 默認情況下,匹配所有的類 */
    @Override
    public boolean matches(Method method, Class<?> clazz) {
        return "driving".equals(method.getName());
    }
    
    /** * 通過覆蓋getClassFilter()方法,讓它僅匹配BenzCar類及其子類 */
    public ClassFilter getClassFilter(){
        return new ClassFilter() {
            /**
             * 切點類 匹配
             * 匹配規則:為BenzCar類或其子類 */
            @Override
            public boolean matches(Class<?> clazz) {
                return BenzCar.class.isAssignableFrom(clazz);
            }
        };
    }
    
}

【driving方法的前置增強類:DrivingBeforeAdvice.java】

package com.Higgin.part4;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

/**
 * Driving的前置增強類
 */
public class DrivingBeforeAdvice implements MethodBeforeAdvice{

    @Override
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("要增強的是:"+obj.getClass()+"類 ---"+method.getName()+"方法");  //得到切點的信息
        System.out.println("【前置增強】做好行駛前的准備工作...");
    }
}

【Spring的xml配置文件:part4.xml】

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
    xmlns:cache="http://www.springframework.org/schema/cache"  
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">
    
    <!-- 要增強的目標對象1 -->
    <bean id="benzTarget" class="com.Higgin.part4.BenzCar"/>
    <!-- 要增強的目標對象2 -->
    <bean id="bmwTarget" class="com.Higgin.part4.BMWCar"/>

    <!-- 前置增強 -->
    <bean id="drivingBeforeAdvice" class="com.Higgin.part4.DrivingBeforeAdvice" />
    
    <!-- 切面 -->
    <bean id="carAdvisor" class="com.Higgin.part4.CarAdvisor"
            p:advice-ref="drivingBeforeAdvice"/>
    
    
    <!-- Spring代理工廠的成員變量配置 -->
    <bean id="parent"  abstract="true" 
         class="org.springframework.aop.framework.ProxyFactoryBean"
        p:interceptorNames="carAdvisor"
        p:proxyTargetClass="true"
    />
    
    <!-- Benz代理 -->
    <bean id="benz" parent="parent" p:target-ref="benzTarget" />
    <!-- BMW代理 -->
    <bean id="bmw" parent="parent" p:target-ref="bmwTarget" /> 
</beans>

【測試類:TestCarAdvisor.java】

package com.Higgin.part4.Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.Higgin.part4.BMWCar;
import com.Higgin.part4.BenzCar;

public class TestCarAdvisor {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("part4.xml");
        
        BenzCar benz= (BenzCar) context.getBean("benz");
        BMWCar bmw=(BMWCar) context.getBean("bmw");
        
        benz.driving();   //奔馳車的driving方法
        System.out.println("===========================");
        bmw.driving();   //寶馬車的driving方法
    }
}

【運行結果】

 

 

【靜態正則表達式方法 匹配切面  例子】

 

【奔馳車類 BenzCar.java】

package com.Higgin.part5;

public class BenzCar {
    public void driving(){
        System.out.println("benz車行駛.....");
    }
    
    public void stop(){
        System.out.println("benz車停止.....");
    }
    
    public void sliding(){
        System.out.println("benz車漂移.....");
    }
}

 

【前置增強類 】

package com.Higgin.part5;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

/**
 * 汽車類的前置增強類
 */
public class CarBeforeAdvice implements MethodBeforeAdvice{

    @Override
    public void before(Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("要增強的是:"+obj.getClass()+"類 ---"+method.getName()+"方法");  //得到切點的信息
        System.out.println("【前置增強】做好行駛前的准備工作...");
    }
}

【Spring的xml匹配 part5.xml】

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
    xmlns:cache="http://www.springframework.org/schema/cache"  
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">
    
    <!-- 要增強的目標對象1 -->
    <bean id="benzTarget" class="com.Higgin.part5.BenzCar"/>

    <!-- 前置增強 -->
    <bean id="drivingBeforeAdvice" class="com.Higgin.part5.CarBeforeAdvice" />
    
    <!-- 正則表達式 匹配 -->
    <bean id="regexAdvisor" 
          class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:advice-ref="drivingBeforeAdvice">
        <property name="patterns">
            <list>
                <value>.*ing.*</value>
            </list>
        </property>
    </bean>
    
    <!-- Spring代理工廠的成員變量配置 -->
    <bean id="benzCar" 
         class="org.springframework.aop.framework.ProxyFactoryBean"
        p:interceptorNames="regexAdvisor"
        p:target-ref="benzTarget"
        p:proxyTargetClass="true"
    />
</beans>

【測試類】

package com.Higgin.part5.Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.Higgin.part5.BenzCar;

public class TestRegexAdvisor {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("part5.xml");
        
        BenzCar benz=(BenzCar) context.getBean("benzCar");
        
        benz.driving();    //匹配.*ing.*
        
        System.out.println("===================================");
        
        benz.sliding();    //匹配.*ing.*
        
        System.out.println("===================================");
        
        benz.stop();       //不匹配
        
    }
}

【運行結果】

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM