<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-88  評論-77  文章-48  trackbacks-0
    Spring Aop Step-By-Step 學(xué)習(xí)筆記(上)
    ?www.uusam.com
    ?
    最近由于工作需要,要求掌握關(guān)于 Spring 方面的東西。所以花了兩個星期的時間來學(xué)習(xí) Spring 的基本知識,主要包括 Ioc Aop 兩方面。
    本文為筆者的 Spring Aop 方面的學(xué)習(xí)筆記,主要結(jié)合了 Spring In Action 第三章 Spring-Reference 第五章 為學(xué)習(xí)向?qū)А8鶕?jù)自己的理解和書中的實例來一步一步完成對于在 Spring Aop 方面的編程。其中基礎(chǔ)部分 Ioc 需要讀者自己參考資料了解,本文將不做描述。
    說明:我將盡量縮短程序長度,在程序部分將減少注釋說明,重點要讀者自己根據(jù)上下文和程序結(jié)果理解體會,具體 api 信息請讀者自己參考 Spring-api 文檔和相關(guān)資料。
    一.??? 準備工作:
    ?
    1.? 開發(fā)環(huán)境:
    l???????????? 適合人群:
    ???????? ???????? 要了解 Spring Ioc ,對 Spring- Aop 可以不了解或者僅僅熟悉 Aop 概念,未參與 Spring Aop 開發(fā)實戰(zhàn)的初學(xué)者。同時也希望高手對于本文的不足或理解錯誤之處給予指點,謝謝。
    l???????????? 開發(fā)環(huán)境:
    JDK 1.4_2
    l???????????? 開發(fā)工具:
    Eclipse 3.12 (未采用任何插件,主要是為初學(xué)者熟悉和理解 xml 文檔的配置)
    l???????????? 所需組件:
    Spring-Framework-1.2.8
    下載地址:
    http://prdownloads.sourceforge.net/springframework/spring-framework-1.2.8-with-dependencies.zip?use_mirror=ufpr
    ?
    2.??? 建立工程:
    ?? 首先用 Eclpse 建立一個普通 java 項目,導(dǎo)入 jar 文件到編譯環(huán)境中,如下:
    a)???????????? Spring.jar Spring 的核心 jar 文件,必須;
    b)???????????? Commons-loggin.jar 日志文件,必須;
    c)???????????? Cglib.jar 動態(tài)代理文件,不是必須(本文需要);
    d)???????????? Jak-oro.jar 使用 Perl Awk 正則表達式進行文本解析工具,不是必須(本文需要);
    建立工程如下:

    好了,下來我們開始我們的 Spring-aop 之旅;
    ?
    二.? Spring -Aop 入門
    ?
    AOP 全名 Aspect-oriented programming Spring framework 是很有前途的 AOP 技術(shù)。作為一種非侵略性的,輕型的 AOP framework ,你無需使用預(yù)編譯器或其他的元標(biāo)簽,便可以在 Java 程序中使用它。這意味著開發(fā)團隊里只需一人要對付 AOP framework ,其他人還是像往常一樣編程。
    關(guān)鍵性概念:
    1)????????? Advice 是代碼的具體實現(xiàn),例如一個實現(xiàn)日志記錄的代碼。
    2)????????? Pointcut 是在將 Advice 插入到程序的條件。
    3)?????????? advisor 是把 pointcut advice 的組合在一起裝配器。
    ?
    圖例:
    你的程序可能如上,現(xiàn)在要在三個流程上同時加入日志控制和權(quán)限控制,如下:
    ?

    ?你的程序可能如上,現(xiàn)在要在三個流程上同時加入日志控制和權(quán)限控制,如下:

    ???????? 其中拿日志為例,日志控制和流程之間的穿插點處叫做連接點( Joinpoint ),而 Advice 就是我們?nèi)罩咎幚淼木唧w代碼, Pointcut 就是定義一個規(guī)則,對三個和業(yè)務(wù)有關(guān)的連接點進行過濾和匹配(例如我們對于業(yè)務(wù) 1 不做日志處理)。 Advisor 就是將符合的規(guī)則的剩下的兩個連接點和具體的日志記錄代碼組合在一起。
    ?
    三.? Spring-Aop 前置通知、后置通知、環(huán)繞通知、異常通知實現(xiàn)
    ?
    我以 Spring In Action 提供的例子進行二次改造,完成我們自己的流程。業(yè)務(wù)流程很簡單,顧客到商店買東西,店員根據(jù)顧客的需要給于顧客提供服務(wù)。實現(xiàn)方法前插入,方法后插入,環(huán)繞,異常四種。
    ?
    ?????? 代碼:
    ???? ???? 建立一個用戶類;
    public class Customer?{
    ???? private String name = " 悠~游!";
    ???? public String getName() {
    ???? ???? return name;
    ???? }
    }
    三個產(chǎn)品
    public class Cheese {
    ?? public String toString(){
    ?? ????? return " 奶酪!";
    ?? }
    }
    public class Pepper {
    ???? public String toString(){
    ???? ???? return " 胡椒粉!";
    ???? }
    }
    public class Squish {
    ???? public String toString(){
    ???? ???? return " 果醬!";
    ???? }
    }
    ????????? 建立一個接口;
    public interface KwikEMart {
    ???? Squish buySquish(Customer customer) throws KwikEMartException;
    ???? Pepper buyPepper(Customer customer) throws KwikEMartException;
    ???? Cheese buyCheese(Customer customer) throws KwikEMartException;
    }
    ?
    實現(xiàn)這個接口,我們實現(xiàn)三個方法,買奶酪,買胡椒粉,買果醬;
    public class ApuKwikEMart implements KwikEMart {
    ???? private boolean cheeseIsEmpty = false;
    ?
    ???? private boolean pepperIsEmpty = false;
    ?
    ???? private boolean squishIsEmpty = false;
    ?
    ???? public Cheese buyCheese(Customer customer) throws NoMoreCheeseException{
    ?
    ???? ???? if (cheeseIsEmpty) {
    ???? ???? ???? throw new NoMoreCheeseException();
    ???? ???? }
    ?
    ???? ???? Cheese s = new Cheese();
    ???? ???? System.out.println("-- 我想買:" + s);
    ???? ???? return s;
    ?
    ???? }
    ?
    ???? public Pepper buyPepper(Customer customer) throws NoMorePepperException{
    ?
    ???? ???? if (pepperIsEmpty) {
    ???? ???? ???? throw new NoMorePepperException();
    ???? ???? }
    ?
    ???? ???? Pepper s = new Pepper();
    ???? ???? System.out.println("-- 我想買:" + s);
    ???? ???? return s;
    ?
    ???? }
    ?
    ???? public Squish buySquish(Customer customer) throws NoMoreSquishException{
    ?
    ???? ???? if (squishIsEmpty) {
    ???? ???? ???? throw new NoMoreSquishException();
    ???? ???? }
    ?
    ???? ???? Squish s = new Squish();
    ???? ???? System.out.println("-- 我想買:" + s);
    ???? ???? return s;
    ?
    ???? }
    ?
    ???? public void setCheeseIsEmpty(boolean cheeseIsEmpty) {
    ???? ???? this.cheeseIsEmpty = cheeseIsEmpty;
    ???? }
    ?
    ???? public void setPepperIsEmpty(boolean pepperIsEmpty) {
    ???? ???? this.pepperIsEmpty = pepperIsEmpty;
    ???? }
    ?
    ???? public void setSquishIsEmpty(boolean squishIsEmpty) {
    ???? ???? this.squishIsEmpty = squishIsEmpty;
    ???? }
    ?
    }
    環(huán)繞通知的實現(xiàn),必須實現(xiàn)invoke方法,通過調(diào)用invoke.proceed()手工調(diào)用對象方法:
    public class OnePerCustomerInterceptor implements MethodInterceptor {
    ????
    ???? private Set customers=new HashSet();
    ?
    ???? public Object invoke(MethodInvocation invoke) throws Throwable {
    ???? ????
    ???? ???? Customer customer=(Customer)invoke.getArguments()[0];
    ???? ???? if(customers.contains(customer)){
    ???? ???? ???? throw new KwikEMartException("One per customer.");
    ???? ???? }
    ???? ????
    ???? ???? System.out.println(" 店員:"+customer.getName() + " ,Can I help you ?");
    ???? ???? Object squishee=invoke.proceed(); // 手工調(diào)用對象方法;
    ???? ???? System.out.println(" 店員:OK! " + customer.getName() + ".give you! " );
    ???? ????
    ???? ???? customers.add(squishee);
    ?
    ???? ???? return squishee;
    ???? }
    }
    前置通知的實現(xiàn);
    public class WelcomeAdvice implements MethodBeforeAdvice {
    ?
    ???? public void before(Method method, Object[] args, Object target) throws Throwable {
    ???? ????
    ???? ???? Customer customer = (Customer) args[0];
    ???? ???? System.out.println(" 店員::Hello " + customer.getName() + " . How are you doing?");
    ?
    ???? }
    }
    public class Customer?{
    ???? private String name = " 悠~游!";
    ???? public String getName() {
    ???? ???? return name;
    ???? }
    }
    后置通知實現(xiàn);
    public class ThankYouAdvice implements AfterReturningAdvice {
    ?
    ???? public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    ???? ????
    ???? ???? Customer customer = (Customer) args[0];
    ???? ???? System.out.println(" 店員:Thank you " + customer.getName() + " . Come again! " );
    ?
    ???? }
    }
    系統(tǒng)異常處理通知實現(xiàn);
    public class KwikEmartExceptionAdvice implements ThrowsAdvice {
    ?
    ???? public void afterThrowing(NoMoreSquishException e) {
    ???? ???? System.out.println(" 系統(tǒng):NoMoreSquisheesException異常截獲了: " + e.getMessage());
    ???? }
    ???? public void afterThrowing(NoMoreCheeseException e) {
    ???? ???? System.out.println(" 系統(tǒng):NoMoreCheeseException異常截獲了: " + e.getMessage());
    ???? }
    ???? public void afterThrowing(NoMorePepperException e) {
    ???? ???? System.out.println(" 系統(tǒng):NoMorePepperException異常截獲了: " + e.getMessage());
    ???? }
    }
    自定義的異常接口;
    public class KwikEMartException extends Exception {
    ?
    ???? private static final long serialVersionUID = -3962577696326432053L;
    ?
    ???? String retValue = "KwikEMartException 異常!";
    ?
    ???? public KwikEMartException(String name) {
    ???? ???? retValue = name;
    ???? }
    ???? public KwikEMartException() {
    ?
    ???? }
    ???? public String getMessage() {
    ???? ???? return retValue;
    ???? }
    ?
    }
    沒有更多的奶酪異常;
    public class NoMoreCheeseException extends KwikEMartException {
    ???? private static final long serialVersionUID = -3961123496322432053L;
    ?
    ???? String retValue = "NoMoreCheeseException 異常!";
    ?
    ???? public NoMoreCheeseException() {
    ???? ???? super();
    ???? }
    ?
    ???? public NoMoreCheeseException(String name) {
    ???? ???? super(name);
    ???? }
    ?
    ???? public String getMessage() {
    ?
    ???? ???? return retValue;
    ???? }
    }
    沒有更多的胡椒粉異常;
    public class NoMorePepperException extends KwikEMartException {
    ???? private static final long serialVersionUID = -3961234696322432053L;
    ?
    ???? String retValue = "NoMorePepperException 異常!";
    ?
    ???? public NoMorePepperException() {
    ???? ???? super();
    ???? }
    ?
    ???? public NoMorePepperException(String name) {
    ???? ???? super(name);
    ???? }
    ?
    ???? public String getMessage() {
    ?
    ???? ???? return retValue;
    ???? }
    }
    沒有更多的果醬異常;
    public class NoMoreSquishException extends KwikEMartException {
    ???? private static final long serialVersionUID = -3121234696322432053L;
    ?
    ???? String retValue = "NoMoreSquishException 異常!";
    ?
    ???? public NoMoreSquishException() {
    ???? ???? super();
    ???? }
    ?
    ???? public NoMoreSquishException(String name) {
    ???? ???? super(name);
    ???? }
    ?
    ???? public String getMessage() {
    ?
    ???? ???? return retValue;
    ???? }
    }
    運行實例類;
    ?????????
    public class RunDemo {
    ?
    ???? ???? ???? public static void kwikEMart() {
    ?
    ???? ???? ???? ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/kwikemart.xml");
    ?
    ???? ???? ???? ???? //如果你想通過類來引用這個的話,就要用到CGLIB.jar了,同時在代理工廠里面設(shè)置:
    ???? ???? ???? ???? //<property name="proxyTargetClass" value="true" />
    ???? ???? ???? ???? KwikEMart akem = (KwikEMart) context.getBean("kwikEMart");
    ????
    ???? ???? ???? ???? try {
    ???? ???? ???? ???? ???? akem.buySquish(new Customer());
    ???? ???? ???? ???? ???? akem.buyPepper(new Customer());
    ???? ???? ???? ???? ???? akem.buyCheese(new Customer());
    ???? ???? ???? ???? } catch (KwikEMartException e) {
    ???? ???? ???? ???? ???? //異常已經(jīng)被截獲了,不信你看控制臺!~;
    ???? ???? ???? ???? }
    ???? ???? ???? }
    ?
    ???? ???? ???? public static void main(String[] args) {
    ???? ???? ???? ???? kwikEMart();
    ???? ???? ???? }
    }
    ???? Xml 文件配置:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    ?
    ?
    <beans>
    ???? <bean id="kwikEMartTarget" class="demo.ApuKwikEMart">
    ???? ???? <!--
    ???? ???? ???? 把這里注釋去掉的話,程序調(diào)用的時候測試異常通知;
    ???? ???? ???? <property name="cheeseIsEmpty">
    ???? ???? ???? ???? <value>true</value>
    ???? ???? ???? </property>
    ???? ???? ???? <property name="pepperIsEmpty">
    ???? ???? ???? ???? <value>true</value>
    ???? ???? ???? </property>
    ???? ???? ???? <property name="squishIsEmpty">
    ???? ???? ???? ???? <value>true</value>
    ???? ???? ???? </property>
    ???? ???? -->
    ???? </bean>
    ?
    ???? <!-- 方法調(diào)用前通知?-->
    ???? <bean id="welcomeAdvice" class="demo.advice.WelcomeAdvice" />
    ???? <!-- 方法調(diào)用后通知 -->
    ???? <bean id="thankYouAdvice" class="demo.advice.ThankYouAdvice" />
    ???? <!-- 環(huán)繞調(diào)用通知?-->
    ???? <bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
    ???? <!-- 異常調(diào)用通知?-->
    ???? <bean id="kwikEmartExceptionAdvice" class="demo.advice.KwikEmartExceptionAdvice" />
    ????
    ???? <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
    ???? ???? <property name="proxyInterfaces" value="demo.KwikEMart" />
    ???? ???? <property name="interceptorNames">
    ???? ???? ???? <list>
    ???? ???? ???? ????
    ???? ???? ???? ???? ???? <value>welcomeAdvice</value>
    ???? ???? ???? ???? ???? <value>thankYouAdvice</value>
    ???? ???? ???? ???? ???? <value>onePerCustomerInterceptor</value>
    ???? ???? ???? ???? ???? <value>kwikEmartExceptionAdvice</value>
    ???? ???? ???? ????
    ???? ???? ???? </list>
    ???? ???? </property>
    ???? ???? <property name="target">
    ???? ???? ???? <ref bean="kwikEMartTarget" />
    ???? ???? </property>
    ???? </bean>
    ?
    </beans>
    ???? 這個例子?xùn)|西很多,不過每個類的代碼都不大。如果你對 org.springframework.aop.framework.ProxyFactoryBean 不是很了解的話可以看我下篇尾處的介紹。 讀清楚之后,我們運行RunDemo 類,查看控制臺結(jié)果,如下:
    ?
    店員::Hello 悠~游! . How are you doing?
    店員:悠~游! ,Can I help you ?
    -- 我想買:果醬!
    店員:OK! 悠~游!.give you!
    店員:Thank you 悠~游! . Come again!
    店員::Hello 悠~游! . How are you doing?
    店員:悠~游! ,Can I help you ?
    -- 我想買:胡椒粉!
    店員:OK! 悠~游!.give you!
    店員:Thank you 悠~游! . Come again!
    店員::Hello 悠~游! . How are you doing?
    店員:悠~游! ,Can I help you ?
    -- 我想買:奶酪!
    店員:OK! 悠~游!.give you!
    店員:Thank you 悠~游! . Come again!
    ?
    ??? 我們將 kwikEMartTarget 里面的注釋去掉,測試異常實現(xiàn),如下:
    ????
    店員::Hello 悠~游! . How are you doing?
    店員:悠~游! ,Can I help you ?
    系統(tǒng):NoMoreSquisheesException異常截獲了: NoMoreSquishException 異常!
    ???? 好好理解一下,我就不廢話了,我們進行下一節(jié)。
    ?
    ?
    ?
    四.?Spring-Aop Pointcut+advice+Advisor 實現(xiàn)
    ?
    我們修改我們的xml文檔后如下:
    ?
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    ?
    <beans>
    ?
    ???? <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
    ?
    ???? <!-- 環(huán)繞調(diào)用通知?-->
    ???? <bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
    ?
    ???? <!-- 使用NameMatchMethodPointcut?-->
    ???? <bean id="nameMatchfilterPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
    ???? ???? <property name="mappedName">
    ???? ???? ???? <!--
    ???? ???? ???? ???? buy.* 以buy開頭的方法;
    ???? ???? ???? -->
    ???? ???? ???? <value>buy*</value>
    ???? ???? </property>
    ???? </bean>
    ?
    ???? <!-- 使用Perl5RegexpMethodPointcut?-->
    ???? <bean id="regexpFilterPointcut" class="org.springframework.aop.support.Perl5RegexpMethodPointcut">
    ???? ???? <property name="pattern">
    ???? ???? ???? <!--
    ???? ???? ???? ???? .*buy.+ 以buy開頭的方法;
    ???? ???? ???? ???? .*buyS.+ 以buyS開頭的方法;
    ???? ???? ???? -->
    ???? ???? ???? <value>.*suy.+</value>
    ???? ???? </property>
    ???? </bean>
    ?
    ???? <bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    ???? ???? <property name="pointcut">
    ???? ???? ???? <ref bean="nameMatchfilterPointcut" />
    ???? ???? </property>
    ???? ???? <property name="advice">
    ???? ???? ???? <ref bean="onePerCustomerInterceptor" />
    ???? ???? </property>
    ???? </bean>
    ???? <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
    ???? ???? <property name="proxyInterfaces" value="demo.KwikEMart" />
    ???? ???? <property name="interceptorNames">
    ???? ???? ???? <list>
    ???? ???? ???? ???? <value>runDemofilterPointcutAdvisor</value>
    ???? ???? ???? </list>
    ???? ???? </property>
    ???? ???? <property name="target">
    ???? ???? ???? <ref bean="kwikEMartTarget" />
    ???? ???? </property>
    ???? </bean>
    ?
    </beans>
    ?
    運行,結(jié)果如下:
    店員:悠~游! ,Can I help you ?
    --我想買:果醬!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    --我想買:胡椒粉!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    --我想買:奶酪!
    ??????? 店員:OK! 悠~游!.give you!
    ?
    在這里簡單說明一下xml文檔:nameMatchfilterPointcutregexpFilterPointcut 是我們自己定義好規(guī)則的Pointcut。nameMatchfilterPointcut 根據(jù)mappedName來設(shè)置過濾規(guī)則, regexpFilterPointcut則是用pattern來設(shè)置過濾規(guī)則。runDemofilterPointcutAdvisor則將我們的Pointcutadvice組合在一起。
    讀者可以自己修改runDemofilterPointcutAdvisorpointcut來切換不同的Pointcut。如果需要RegexpMethodPointcut 的子類的實現(xiàn),必須要oro包支持。(注:RegexpMethodPointcut有倆個子類的實現(xiàn),JdkRegexpMethodPointcut和Perl5RegexpMethodPointcut)。
    ???? 但是,如果我們想讓我們的Advisor同時實現(xiàn)多個Pointcut+advice怎么辦呢?利用Spring In Action里面的實例,我們來自己實現(xiàn)我們的Pointcut
    ?
    ??? 代碼:
    ?
    ?
    public class MyUnionPointcut implements Pointcut {
    ????
    ???? private Pointcut delegate;
    ?
    ???? public ClassFilter getClassFilter() {
    ???? ???? return getDelegate().getClassFilter();
    ???? }
    ?
    ???? private Pointcut getDelegate() {
    ???? ???? if (delegate == null) {
    ???? ???? ???? throw new AopConfigException("No pointcuts have been configured.");
    ???? ???? }
    ???? ???? return delegate;
    ???? }
    ?
    ???? public MethodMatcher getMethodMatcher() {
    ???? ???? return getDelegate().getMethodMatcher();
    ???? }
    ?
    ???? public void setPointcuts(List pointcuts) {
    ?
    ???? ???? if (pointcuts == null || pointcuts.size() == 0) {
    ???? ???? ???? throw new AopConfigException("Must have at least one Pointcut.");
    ???? ???? }
    ???? ???? delegate = (Pointcut) pointcuts.get(0);
    ?
    ???? ???? for (int i = 1; i < pointcuts.size(); i++) {
    ???? ???? ???? Pointcut pointcut = (Pointcut) pointcuts.get(i);
    ???? ???? ???? delegate = Pointcuts.union(delegate, pointcut);
    ???? ???? }
    ?
    ???? }
    }
    ?
    其實就是繼承Pointcut類,實現(xiàn)getMethodMatcher()方法即可,接下來看我們把那兩個Pointcut組合成一個,當(dāng)其中一個Pointcut滿足的時候就返回true,調(diào)用我們的Advice。
    ?
    在xml中,加入下面代碼:
    ?
    ?
    ???? <bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
    ???? ???? <property name="pointcuts">
    ???? ???? ???? <list>
    ???? ???? ???? <!-- 這里說明一下:動態(tài)切入點和靜態(tài)切入點集合在一起的時候好像有問題? -->
    ???? ???? ???? ???? <ref bean="nameMatchfilterPointcut" />
    ???? ???? ???? ???? <ref bean="regexpFilterPointcut" />
    ???? ???? ???? </list>?
    ???? ???? </property>
    ???? </bean>
    修改runDemofilterPointcutAdvisorpointcut來加入我們組合好的Pointcut
    ?
    ???? <bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    ???? ???? <property name="pointcut">
    ???? ???? ???? <ref bean=”myUnionPointcut" />
    ???? ???? </property>
    ???? ???? <property name="advice">
    ???? ???? ???? <ref bean="onePerCustomerInterceptor" />
    ???? ???? </property>
    ???? </bean>
    ?
    同時在運行前,讀者可以自己修改兩個pointcut的匹配方法,來匹配更多的可選項。同時可以參考的一個類是org.springframework.aop.support.UnionPointcut,它實現(xiàn)兩個pointcut的聯(lián)合。如果讀者想實現(xiàn)更加靈活的匹配,需要自己來定義自己的pointcut。(如第一個pointcut交叉第二個pointcut,聯(lián)合第三個pointcut),交叉的工具類為ComposablePointcut。
    運行的結(jié)果請讀者自己試驗。這個時候您可能在想,這些pointcut都是Spring自己的實現(xiàn),我們能否自己來定義我們自己規(guī)則的pointcut呢?當(dāng)然可以!~
    代碼:
    /**
    ?*
    ?* 自己定義的靜態(tài)切入點
    ?* 滿足條件是:當(dāng)傳入的數(shù)字大于1塊錢的時候才可以;
    ?*
    ?* @author 悠~游
    ?* @since 2006-06-22
    ?* @link www.uusam.com
    ?*/
    public class MyPointcut extends StaticMethodMatcherPointcut implements Serializable {
    ?
    ???? private static final long serialVersionUID = -101281038294508751L;
    ?
    ???? private int money = 0;
    ?
    ???? /**
    ???? ?* 實現(xiàn)方法,業(yè)務(wù)邏輯為:根據(jù)輸入的錢數(shù)和動作(必須是以buy開頭的方法),來確定是否有錢購買商品,買完之后去掉商品的價格;
    ???? ?*/
    ???? public boolean matches(Method method, Class targetClass) {
    ???? ???? if (method.getName().indexOf("buyCheese") == 0 && money >= 100) {
    ???? ???? ???? money -= 100;
    ???? ???? ???? return true;
    ???? ???? } else if (method.getName().indexOf("buyPepper") == 0 && money >= 5) {
    ???? ???? ???? money -= 5;
    ???? ???? ???? return true;
    ???? ???? } else if (method.getName().indexOf("buySquish") == 0 && money >= 10) {
    ???? ???? ???? money -= 10;
    ???? ???? ???? return true;
    ???? ???? }
    ???? ???? System.out.println("門衛(wèi):你要買的東西太貴,你的錢 "+money+" 太少!~ ,取消服務(wù)!");
    ???? ???? return false;
    ???? }
    ?
    ???? public void setMoney(int money) {
    ???? ???? this.money = money;
    ???? }
    ?
    }
    ?
    這個就是我們自己定義的靜態(tài)Pointcut,主要實現(xiàn)自己的matches方法。看看如何加入到我們的XML文檔中:
    ?
    ???? <!-- 使用自定義的切入點?-->
    ???? <bean id="myPointcut" class="demo.pointcut.MyPointcut">
    ???? ???? <property name="money">
    ???? ???? ???? <value>100</value>
    ???? ???? </property>
    ???? </bean>
    ?
    很簡單不是么?我們定義一個數(shù)字,就是用戶的money,進入商店時候兜里的錢^_^。同樣修改我們的myUnionPointcut里面的pointcuts,加入我們的pointcut。
    ?
    ????
    <bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
    ???? ???? <property name="pointcuts">
    ???? ???? ???? <list>
    ???? ???? ???? ???? <!—上面兩個要設(shè)置成不通過哦,或者索性就去掉先。 -->
    ???? ???? ???? ???? <ref bean="nameMatchfilterPointcut" />
    ???? ???? ???? ???? <ref bean="regexpFilterPointcut" />
    <ref bean="myPointcut" />
    ???? ???? ???? </list>?
    ???? ???? </property>
    ???? </bean>
    ????
    當(dāng)上面兩個Pointcut定義的規(guī)則不通過的時候,程序開始校驗我們的myPointcut。運行,結(jié)果如下:
    店員:悠~游! ,Can I help you ?
    --我想買:果醬!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    --我想買:胡椒粉!
    店員:OK! 悠~游!.give you!
    門衛(wèi):你要買的東西太貴,你的錢 85 太少!~ , 取消服務(wù)!
    --我想買:奶酪!//服務(wù)員沒了...
    ????
    ???? 好了,是不是我們想要的結(jié)果呢?呵呵。
    ???? 同時,Spring 提供動態(tài)Pointcut。關(guān)于動態(tài)的說明我就不在熬述了,我們這里只關(guān)心具體Spring帶給我們的具體實現(xiàn)方法,具體應(yīng)用請讀者自己斟酌使用。
    ????
    ?
    ???? <!-- 定制動態(tài)接入點,來判斷當(dāng)前線程堆棧中是否有demo.RunDemo這個類;?-->
    ???? <bean id="runDemoPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
    ???? ???? <constructor-arg>
    ???? ???? ???? <value>demo.RunDemo</value>
    ???? ???? </constructor-arg>
    ???? </bean>
    ???? 修改下面的引用我們的動態(tài)Pointcut;
    <bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
    ???? ???? <property name="pointcuts">
    <list>
    ???? <ref bean=" runDemoPointcut " />
    ??? ???? </list>?
    ??? </property>
    </bean>
    ?
    ???? 運行,結(jié)果如下:
    店員:悠~游! ,Can I help you ?
    --我想買:果醬!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    --我想買:胡椒粉!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    --我想買:奶酪!
    店員:OK! 悠~游!.give you!
    ????
    ???? 動態(tài)切入點是根據(jù)當(dāng)前堆棧信息進行方法匹配的一種規(guī)則,讀者可以自己修改demo.RunDemo,如java.lang.Integer,來看看結(jié)果。
    ?
    --我想買:果醬!
    --我想買:胡椒粉!
    --我想買:奶酪!
    ????
    ???? 到這里能夠讀下來已經(jīng)很不容易了,呵呵。還是站起來走動一下吧,接下來我們將搞定其他的一些東東。

    posted on 2006-07-05 17:26 崛起的程序員 閱讀(350) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 拔擦拔擦8x华人免费久久| 2022久久国产精品免费热麻豆| 国产又黄又爽又大的免费视频 | 亚洲黄色网址在线观看| 亚洲国产亚洲综合在线尤物| 亚洲欧美日韩综合久久久久| 成人在线免费视频| 成人电影在线免费观看| 国产精品免费网站| 色视频色露露永久免费观看| 亚洲性日韩精品一区二区三区| 亚洲AV日韩精品久久久久久久| 亚洲国产成人久久| 一级毛片在播放免费| 无码av免费一区二区三区| 成人a免费α片在线视频网站| 亚洲av区一区二区三| 亚洲色图在线播放| 亚洲AV无码一区二区大桥未久| 国产一级a毛一级a看免费人娇| 麻豆国产精品免费视频| 免费中文字幕一级毛片| 亚洲夜夜欢A∨一区二区三区| 亚洲精品视频在线观看视频| 白白色免费在线视频| 免费无码一区二区三区| 成人永久免费福利视频网站| 精品国产亚洲一区二区三区 | 亚洲人成在线播放| 无码日韩人妻AV一区免费l| 91在线手机精品免费观看| 国产成人免费全部网站| 久久狠狠高潮亚洲精品| 视频一区在线免费观看| 五月婷婷在线免费观看| 亚洲人成网站观看在线播放| 亚洲一级黄色大片| 成在线人免费无码高潮喷水| 女人张开腿给人桶免费视频| 亚洲成A人片在线观看无码不卡 | 久久精品成人免费观看97|