Spring Aop Step-By-Step
學(xué)習(xí)筆記(上)
?
最近由于工作需要,要求掌握關(guān)于
Spring
方面的東西。所以花了兩個(gè)星期的時(shí)間來(lái)學(xué)習(xí)
Spring
的基本知識(shí),主要包括
Ioc
和
Aop
兩方面。
本文為筆者的
Spring
在
Aop
方面的學(xué)習(xí)筆記,主要結(jié)合了
Spring In Action
第三章
和
Spring-Reference
第五章
為學(xué)習(xí)向?qū)А8鶕?jù)自己的理解和書中的實(shí)例來(lái)一步一步完成對(duì)于在
Spring
中
Aop
方面的編程。其中基礎(chǔ)部分
Ioc
需要讀者自己參考資料了解,本文將不做描述。
說(shuō)明:我將盡量縮短程序長(zhǎng)度,在程序部分將減少注釋說(shuō)明,重點(diǎn)要讀者自己根據(jù)上下文和程序結(jié)果理解體會(huì),具體
api
信息請(qǐng)讀者自己參考
Spring-api
文檔和相關(guān)資料。
一.???
準(zhǔn)備工作:
?
1.?
開(kāi)發(fā)環(huán)境:
l????????????
適合人群:
???????? ????????
要了解
Spring Ioc
,對(duì)
Spring- Aop
可以不了解或者僅僅熟悉
Aop
概念,未參與
Spring Aop
開(kāi)發(fā)實(shí)戰(zhàn)的初學(xué)者。同時(shí)也希望高手對(duì)于本文的不足或理解錯(cuò)誤之處給予指點(diǎn),謝謝。
l????????????
開(kāi)發(fā)環(huán)境:
JDK 1.4_2
l????????????
開(kāi)發(fā)工具:
Eclipse 3.12
(未采用任何插件,主要是為初學(xué)者熟悉和理解
xml
文檔的配置)
l????????????
所需組件:
Spring-Framework-1.2.8
下載地址:
?
2.???
建立工程:
??
首先用
Eclpse
建立一個(gè)普通
java
項(xiàng)目,導(dǎo)入
jar
文件到編譯環(huán)境中,如下:
a)????????????
Spring.jar
為
Spring
的核心
jar
文件,必須;
b)????????????
Commons-loggin.jar
日志文件,必須;
c)????????????
Cglib.jar
動(dòng)態(tài)代理文件,不是必須(本文需要);
d)????????????
Jak-oro.jar
使用
Perl
和
Awk
正則表達(dá)式進(jìn)行文本解析工具,不是必須(本文需要);
建立工程如下:
好了,下來(lái)我們開(kāi)始我們的
Spring-aop
之旅;
?
二.?
Spring -Aop
入門
?
AOP
全名
Aspect-oriented programming
。
Spring framework
是很有前途的
AOP
技術(shù)。作為一種非侵略性的,輕型的
AOP framework
,你無(wú)需使用預(yù)編譯器或其他的元標(biāo)簽,便可以在
Java
程序中使用它。這意味著開(kāi)發(fā)團(tuán)隊(duì)里只需一人要對(duì)付
AOP framework
,其他人還是像往常一樣編程。
關(guān)鍵性概念:
1)?????????
Advice
是代碼的具體實(shí)現(xiàn),例如一個(gè)實(shí)現(xiàn)日志記錄的代碼。
2)?????????
Pointcut
是在將
Advice
插入到程序的條件。
3)??????????
advisor
是把
pointcut
和
advice
的組合在一起裝配器。
?
圖例:
你的程序可能如上,現(xiàn)在要在三個(gè)流程上同時(shí)加入日志控制和權(quán)限控制,如下:
?
?你的程序可能如上,現(xiàn)在要在三個(gè)流程上同時(shí)加入日志控制和權(quán)限控制,如下:

????????
其中拿日志為例,日志控制和流程之間的穿插點(diǎn)處叫做連接點(diǎn)(
Joinpoint
),而
Advice
就是我們?nèi)罩咎幚淼木唧w代碼,
Pointcut
就是定義一個(gè)規(guī)則,對(duì)三個(gè)和業(yè)務(wù)有關(guān)的連接點(diǎn)進(jìn)行過(guò)濾和匹配(例如我們對(duì)于業(yè)務(wù)
1
不做日志處理)。
Advisor
就是將符合的規(guī)則的剩下的兩個(gè)連接點(diǎn)和具體的日志記錄代碼組合在一起。
?
三.?
Spring-Aop
前置通知、后置通知、環(huán)繞通知、異常通知實(shí)現(xiàn)
?
我以
Spring In Action
提供的例子進(jìn)行二次改造,完成我們自己的流程。業(yè)務(wù)流程很簡(jiǎn)單,顧客到商店買東西,店員根據(jù)顧客的需要給于顧客提供服務(wù)。實(shí)現(xiàn)方法前插入,方法后插入,環(huán)繞,異常四種。
?
??????
代碼:
???? ????
建立一個(gè)用戶類;
public class Customer?{
???? private String name = "
悠~游!";
???? public String getName() {
???? ???? return name;
???? }
}
三個(gè)產(chǎn)品
public class Cheese {
?? public String toString(){
?? ????? return "
奶酪!";
?? }
}
public class Pepper {
???? public String toString(){
???? ???? return "
胡椒粉!";
???? }
}
public class Squish {
???? public String toString(){
???? ???? return "
果醬!";
???? }
}
?????????
建立一個(gè)接口;
public interface KwikEMart {
???? Squish buySquish(Customer customer) throws KwikEMartException;
???? Pepper buyPepper(Customer customer) throws KwikEMartException;
???? Cheese buyCheese(Customer customer) throws KwikEMartException;
}
?
實(shí)現(xiàn)這個(gè)接口,我們實(shí)現(xiàn)三個(gè)方法,買奶酪,買胡椒粉,買果醬;
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)繞通知的實(shí)現(xiàn),必須實(shí)現(xiàn)invoke方法,通過(guò)調(diào)用invoke.proceed()手工調(diào)用對(duì)象方法:
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)用對(duì)象方法;
???? ???? System.out.println("
店員:OK! " + customer.getName() + ".give you! " );
???? ????
???? ???? customers.add(squishee);
?
???? ???? return squishee;
???? }
}
前置通知的實(shí)現(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;
???? }
}
后置通知實(shí)現(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)異常處理通知實(shí)現(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;
???? }
?
}
沒(méi)有更多的奶酪異常;
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;
???? }
}
沒(méi)有更多的胡椒粉異常;
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;
???? }
}
沒(méi)有更多的果醬異常;
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;
???? }
}
運(yùn)行實(shí)例類;
????????? public class RunDemo {
?
???? ???? ???? public static void kwikEMart() {
?
???? ???? ???? ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/kwikemart.xml");
?
???? ???? ???? ???? //如果你想通過(guò)類來(lái)引用這個(gè)的話,就要用到CGLIB.jar了,同時(shí)在代理工廠里面設(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)被截獲了,不信你看控制臺(tái)!~;
???? ???? ???? ???? }
???? ???? ???? }
?
???? ???? ???? 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)用的時(shí)候測(cè)試異常通知;
???? ???? ???? <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>
????
這個(gè)例子?xùn)|西很多,不過(guò)每個(gè)類的代碼都不大。如果你對(duì)
org.springframework.aop.framework.ProxyFactoryBean
不是很了解的話可以看我下篇尾處的介紹。
讀清楚之后,我們運(yùn)行RunDemo 類,查看控制臺(tái)結(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
里面的注釋去掉,測(cè)試異常實(shí)現(xiàn),如下:
????
店員::Hello 悠~游! . How are you doing?
店員:悠~游! ,Can I help you ?
系統(tǒng):NoMoreSquisheesException異常截獲了: NoMoreSquishException 異常!
????
好好理解一下,我就不廢話了,我們進(jìn)行下一節(jié)。
?
?
?
四.?Spring-Aop 之Pointcut+advice+Advisor 實(shí)現(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開(kāi)頭的方法;
???? ???? ???? -->
???? ???? ???? <value>buy*</value>
???? ???? </property>
???? </bean>
?
???? <!-- 使用Perl5RegexpMethodPointcut?-->
???? <bean id="regexpFilterPointcut" class="org.springframework.aop.support.Perl5RegexpMethodPointcut">
???? ???? <property name="pattern">
???? ???? ???? <!--
???? ???? ???? ???? .*buy.+ 以buy開(kāi)頭的方法;
???? ???? ???? ???? .*buyS.+ 以buyS開(kāi)頭的方法;
???? ???? ???? -->
???? ???? ???? <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>
?
運(yùn)行,結(jié)果如下:
店員:悠~游! ,Can I help you ?
--我想買:果醬!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:胡椒粉!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:奶酪!
??????? 店員:OK! 悠~游!.give you!
?
在這里簡(jiǎn)單說(shuō)明一下xml文檔:nameMatchfilterPointcut和regexpFilterPointcut 是我們自己定義好規(guī)則的Pointcut。nameMatchfilterPointcut 根據(jù)mappedName來(lái)設(shè)置過(guò)濾規(guī)則, regexpFilterPointcut則是用pattern來(lái)設(shè)置過(guò)濾規(guī)則。runDemofilterPointcutAdvisor則將我們的Pointcut和advice組合在一起。
讀者可以自己修改runDemofilterPointcutAdvisor的pointcut來(lái)切換不同的Pointcut。如果需要RegexpMethodPointcut 的子類的實(shí)現(xiàn),必須要oro包支持。(注:RegexpMethodPointcut有倆個(gè)子類的實(shí)現(xiàn),JdkRegexpMethodPointcut和Perl5RegexpMethodPointcut)。
???? 但是,如果我們想讓我們的Advisor同時(shí)實(shí)現(xiàn)多個(gè)Pointcut+advice怎么辦呢?利用Spring In Action里面的實(shí)例,我們來(lái)自己實(shí)現(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);
???? ???? }
?
???? }
}
?
其實(shí)就是繼承Pointcut類,實(shí)現(xiàn)getMethodMatcher()方法即可,接下來(lái)看我們把那兩個(gè)Pointcut組合成一個(gè),當(dāng)其中一個(gè)Pointcut滿足的時(shí)候就返回true,調(diào)用我們的Advice。?
在xml中,加入下面代碼:
?
?
???? <bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
???? ???? <property name="pointcuts">
???? ???? ???? <list>
???? ???? ???? <!-- 這里說(shuō)明一下:動(dòng)態(tài)切入點(diǎn)和靜態(tài)切入點(diǎn)集合在一起的時(shí)候好像有問(wèn)題? -->
???? ???? ???? ???? <ref bean="nameMatchfilterPointcut" />
???? ???? ???? ???? <ref bean="regexpFilterPointcut" />
???? ???? ???? </list>?
???? ???? </property>
???? </bean>
修改runDemofilterPointcutAdvisor的pointcut來(lái)加入我們組合好的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>
?
同時(shí)在運(yùn)行前,讀者可以自己修改兩個(gè)pointcut的匹配方法,來(lái)匹配更多的可選項(xiàng)。同時(shí)可以參考的一個(gè)類是org.springframework.aop.support.UnionPointcut,它實(shí)現(xiàn)兩個(gè)pointcut的聯(lián)合。如果讀者想實(shí)現(xiàn)更加靈活的匹配,需要自己來(lái)定義自己的pointcut。(如第一個(gè)pointcut交叉第二個(gè)pointcut,聯(lián)合第三個(gè)pointcut),交叉的工具類為ComposablePointcut。運(yùn)行的結(jié)果請(qǐng)讀者自己試驗(yàn)。這個(gè)時(shí)候您可能在想,這些pointcut都是Spring自己的實(shí)現(xiàn),我們能否自己來(lái)定義我們自己規(guī)則的pointcut呢?當(dāng)然可以!~
代碼:
/**
?*
?* 自己定義的靜態(tài)切入點(diǎn)
?* 滿足條件是:當(dāng)傳入的數(shù)字大于1塊錢的時(shí)候才可以;
?*
?* @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;
?
???? /**
???? ?* 實(shí)現(xiàn)方法,業(yè)務(wù)邏輯為:根據(jù)輸入的錢數(shù)和動(dòng)作(必須是以buy開(kāi)頭的方法),來(lái)確定是否有錢購(gòu)買商品,買完之后去掉商品的價(jià)格;
???? ?*/
???? 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;
???? }
?
}
?
這個(gè)就是我們自己定義的靜態(tài)Pointcut,主要實(shí)現(xiàn)自己的matches方法。看看如何加入到我們的XML文檔中:?
???? <!-- 使用自定義的切入點(diǎn)?-->
???? <bean id="myPointcut" class="demo.pointcut.MyPointcut">
???? ???? <property name="money">
???? ???? ???? <value>100</value>
???? ???? </property>
???? </bean>
?
很簡(jiǎn)單不是么?我們定義一個(gè)數(shù)字,就是用戶的money,進(jìn)入商店時(shí)候兜里的錢^_^。同樣修改我們的myUnionPointcut里面的pointcuts,加入我們的pointcut。
?
????<bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
???? ???? <property name="pointcuts">
???? ???? ???? <list>
???? ???? ???? ???? <!—上面兩個(gè)要設(shè)置成不通過(guò)哦,或者索性就去掉先。 -->
???? ???? ???? ???? <ref bean="nameMatchfilterPointcut" />
???? ???? ???? ???? <ref bean="regexpFilterPointcut" />
<ref bean="myPointcut" />
???? ???? ???? </list>?
???? ???? </property>
???? </bean>
???? 當(dāng)上面兩個(gè)Pointcut定義的規(guī)則不通過(guò)的時(shí)候,程序開(kāi)始校驗(yàn)我們的myPointcut。運(yùn)行,結(jié)果如下:
店員:悠~游! ,Can I help you ?
--我想買:果醬!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:胡椒粉!
店員:OK! 悠~游!.give you!
門衛(wèi):你要買的東西太貴,你的錢 85 太少!~ , 取消服務(wù)!
--我想買:奶酪!//服務(wù)員沒(méi)了...
????
???? 好了,是不是我們想要的結(jié)果呢?呵呵。
???? 同時(shí),Spring 提供動(dòng)態(tài)Pointcut。關(guān)于動(dòng)態(tài)的說(shuō)明我就不在熬述了,我們這里只關(guān)心具體Spring帶給我們的具體實(shí)現(xiàn)方法,具體應(yīng)用請(qǐng)讀者自己斟酌使用。
???? ?
???? <!-- 定制動(dòng)態(tài)接入點(diǎn),來(lái)判斷當(dāng)前線程堆棧中是否有demo.RunDemo這個(gè)類;?-->
???? <bean id="runDemoPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
???? ???? <constructor-arg>
???? ???? ???? <value>demo.RunDemo</value>
???? ???? </constructor-arg>
???? </bean>
???? 修改下面的引用我們的動(dòng)態(tài)Pointcut; <bean id="myUnionPointcut" class="demo.utils.MyUnionPointcut">
???? ???? <property name="pointcuts">
<list>
???? <ref bean=" runDemoPointcut " />
??? ???? </list>?
??? </property>
</bean>
?
???? 運(yùn)行,結(jié)果如下:
店員:悠~游! ,Can I help you ?
--我想買:果醬!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:胡椒粉!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:奶酪!
店員:OK! 悠~游!.give you!
????
???? 動(dòng)態(tài)切入點(diǎn)是根據(jù)當(dāng)前堆棧信息進(jìn)行方法匹配的一種規(guī)則,讀者可以自己修改demo.RunDemo,如java.lang.Integer,來(lái)看看結(jié)果。
?
--我想買:果醬!
--我想買:胡椒粉!
--我想買:奶酪!
????
???? 到這里能夠讀下來(lái)已經(jīng)很不容易了,呵呵。還是站起來(lái)走動(dòng)一下吧,接下來(lái)我們將搞定其他的一些東東。
posted on 2006-07-05 17:26
崛起的程序員 閱讀(350)
評(píng)論(0) 編輯 收藏