熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

Java編程—Spring AOP本質(6)

2022-06-13   來源: Java開源技術 

    在前面四個例子中只要實現一個Advice然後調用ProxyFactoryaddAdvice()方法為代理設定通知不用設置切入點從代理對上調用的方法就被通知到了其原因就在於執行addAdvice()方法時ProxyFactory會將Advice對象委派給addAdvistor()方法後台會自動創建一個DefaultPointcutAdvistor實例並將Advice加入其中而默認的DefaultPointcutAdvistor會將切入點設為所有的方法
 
假如我們不想通過代理來執行某些方法也就是說在執行某些方法的時候不通知這時候該如何實現呢?
Spring提供一系列接口來實現這個目標最主要的接口如下
implements orgspringframeworkaopPointcut
orgspringframeworkaopClassFilter
orgspringframeworkaopMethodMatcher
 
下面看看幾個關鍵接口的定義
 
切入點(Pointcut)
 
/**
* 切入點
*/
public interface Pointcut {
    //切入點的一個單例
    public static final Pointcut TRUE = TruePointcutINSTANCE;  
    //類過濾器  
    public ClassFilter getClassFilter();
    //方法過濾器
    public MethodMatcher getMethodMatcher();
}
 

/**
* 類過濾器
*/
public interface ClassFilter {
    //類過濾器單例
    public static final ClassFilter TRUE = TrueClassFilterINSTANCE;
    //類匹配方法
    public boolean matches(Class class);
}
 

/**
* 方法過濾器
*/
public interface MethodMatcher {
    //方法過濾器單例
    public static final MethodMatcher TRUE = TrueMethodMatcherINSTANCE;
    //靜態方法匹配方法
    public boolean matches(Method method Class class);
    //判斷靜態還是動態匹配返回true動態匹配false靜態匹配
    public boolean isRuntime();
    //對象(動態)匹配方法
    public boolean matches(Method method Class class Object aobj[]);
}
 
通知者(Advisor)
 

/**
* 通知者接口
*/
public interface Advisor {
    //切面是否為per instance
    public boolean isPerInstance();
    //獲取切面上的通知
    public Advice getAdvice();
}
 

/**
* 通知者子接口Spring中標准的切面都應該實現此接口
*/
public PointcutAdvisor extends Advisor {
    //獲取通知者的切點
    public Pointcut getPointcut();
}
 
為了看的明白還是回顧一下框架圖

 
 


還有很多接口和類沒有畫出這裡簡要說明下
 
在orgspringframeworkaopsupport包下還有一些很重要的切點類是Spring定義好的幾乎可以滿足所用應用的需要
DynamicMethodMatcherPointcut
NameMatchMethodPointcut
PerlRegexpMethodPointcut
StaticMethodMatcherPointcut
JdkRegexpMethodPointcut
ControlFlowPointcut
ComposablePointcut
 
與這些切點對應還有一些切面類名字都是以PointcutAdvisor結尾
 
通過上面的原理圖簡單查看一下API就可以直到通過通知Advice和切點Pointcut可以生成通知者Advisor有了通知者有了目標對象就可以通過ProxyFactory生成代理對象
 
下面給個例子看看Spring如何通過切點來選取類和方法的並如通知所選取的方法
 
例子擴展StaticMethodMatcherPointcut實現靜態切入點過濾
 

/**
* 業務組件BeanOne
*/
public class BeanOne {
    public void foo() {
        Systemoutprintln(BeanOne的foo()被調用!);
    }    
    public void bar() {
        Systemoutprintln(BeanOne的bar()被調用!);
    }
}
 

/**
* 業務組件BeanTwo
*/
public class BeanTwo {
    public void foo() {
        Systemoutprintln(BeanTwo的foo()被調用!);
    }    
    public void bar() {
        Systemoutprintln(BeanTwo的bar()被調用!);
    }
}
 

import orgaopallianceinterceptMethodInterceptor;
import orgaopallianceinterceptMethodInvocation;

/**
* 自定義通知Advice
*/
public class SimpleAdvice implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Systemoutprintln(>> 業務方法調用前動作被代理調用目標方法是 + invocationgetMethod()getName());
        Object retVal = invocationproceed();
        Systemoutprintln(>> 業務方法調用結束後動作!);
        return retVal;
    }
}
 

import javalangreflectMethod;
import orgspringframeworkaopClassFilter;
import orgspringframeworkaopsupportStaticMethodMatcherPointcut;

/**
* 自定義靜態切入點Pointcut
*/
public class SimpleStaticPointcut extends StaticMethodMatcherPointcut {

    public boolean matches(Method method Class cls) {
        //類方法名為foo時候匹配
        Systemoutprintln(切入點方法匹配正在匹配+clsgetName()++methodgetName()+方法!);
        return (fooequals(methodgetName()));
    }

    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            public boolean matches(Class cls) {
                Systemoutprintln(切入點類匹配正在匹配+clsgetName()+類!);
                //BeanOne類匹配
                return (cls == BeanOneclass);
            }
        };
    }
}


 

import orgaopallianceaopAdvice;
import orgspringframeworkaopAdvisor;
import orgspringframeworkaopPointcut;
import orgspringframeworkaopframeworkProxyFactory;
import orgspringframeworkaopsupportDefaultPointcutAdvisor;

/**
* 客戶端測試
*/
public class StaticPointcutExample {

    public static void main(String[] args) {
        //創建目標對象
        BeanOne one = new BeanOne();
        BeanTwo two = new BeanTwo();

        //定義代理對象
        BeanOne proxyOne;
        BeanTwo proxyTwo;

        //創建一個切入點
        Pointcut pc = new SimpleStaticPointcut();
        //創建一個通知
        Advice advice = new SimpleAdvice();
        //創建一個通知者(即通知和切入點的結合)
        Advisor advisor = new DefaultPointcutAdvisor(pc advice);

        //創建一個代理工廠
        ProxyFactory pf = new ProxyFactory();
        //將方面加入工廠
        pfaddAdvisor(advisor);
        //將目標加入工廠
        pfsetTarget(one);
        //獲取代理對象產品
        proxyOne = (BeanOne) pfgetProxy();  //這個時候會進行匹配檢查

        //創建一個代理工廠
        pf = new ProxyFactory();
        pfaddAdvisor(advisor);
        pfsetTarget(two);
        proxyTwo = (BeanTwo) pfgetProxy();

        /*
       orgspringframeworkaopframeworkProxyFactory中
       設置的代理目標一次僅能一個這點不要犯迷糊我查過源碼了
      */

        //從代理產品上調用目標方法
        proxyOnefoo();
        proxyTwofoo();

        proxyOnebar();
        proxyTwobar();

    }
}
 
運行結果

Using JDK collections
切入點類匹配正在匹配comapressprospringchstaticpcBeanOne類!
切入點方法匹配正在匹配comapressprospringchstaticpcBeanOne的foo方法!
切入點類匹配正在匹配comapressprospringchstaticpcBeanOne類!
切入點方法匹配正在匹配comapressprospringchstaticpcBeanOne的bar方法!
切入點類匹配正在匹配comapressprospringchstaticpcBeanOne類!
切入點方法匹配正在匹配comapressprospringchstaticpcBeanOne的hashCode方法!
切入點類匹配正在匹配comapressprospringchstaticpcBeanOne類!
切入點方法匹配正在匹配comapressprospringchstaticpcBeanOne的toString方法!
切入點類匹配正在匹配comapressprospringchstaticpcBeanTwo類!
切入點類匹配正在匹配comapressprospringchstaticpcBeanTwo類!
切入點類匹配正在匹配comapressprospringchstaticpcBeanTwo類!
切入點類匹配正在匹配comapressprospringchstaticpcBeanTwo類!
切入點類匹配正在匹配comapressprospringchstaticpcBeanOne類!
切入點方法匹配正在匹配comapressprospringchstaticpcBeanOne的foo方法!
>> 業務方法調用前動作被代理調用目標方法是 foo
BeanOne的foo()被調用!
>> 業務方法調用結束後動作!
BeanTwo的foo()被調用!
BeanOne的bar()被調用!
BeanTwo的bar()被調用!

Process finished with exit code


From:http://tw.wingwit.com/Article/program/Java/ky/201311/11164.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.