轉(zhuǎn)載自: http://chenjumin.iteye.com/blog/364948
?
一、基礎(chǔ)接口和類(lèi)
???? 1、Person接口的源碼
- public ? interface ?Person?{??
- ???? public ? void ?info();??
- ???? public ? void ?show(String?message);??
- }??
public interface Person { public void info(); public void show(String message); }
?
???? 2、PersonImpl類(lèi)的源碼
- public ? class ?PersonImpl? implements ?Person?{??
- ???? private ?String?name;??
- ???? private ? int ?age;??
- ??????
- ???? public ? void ?setName(String?name)?{??
- ???????? this .name?=?name;??
- ????}??
- ??
- ???? public ? void ?setAge( int ?age)?{??
- ???????? this .age?=?age;??
- ????}??
- ??
- ???? public ? void ?info()?{??
- ????????System.out.println( "\t我叫" ?+?name?+? ",今年" ?+?age?+? "歲。" );??
- ????}??
- ??
- ???? public ? void ?show(String?message)?{??
- ????????System.out.println(message);??
- ????}??
- }??
public class PersonImpl implements Person { private String name; private int age; public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void info() { System.out.println("\t我叫" + name + ",今年" + age + "歲。"); } public void show(String message) { System.out.println(message); } }
?
??? 3、bean的配置
- <!--?目標(biāo)對(duì)象?--> ??
- < bean ? id = "personTarget" ? class = "com.cjm.aop.PersonImpl" > ??
- ???? < property ? name = "name" ? value = "Raymond.chen" /> ??
- ???? < property ? name = "age" ? value = "30" /> ??
- </ bean > ??
<!-- 目標(biāo)對(duì)象 --> <bean id="personTarget" class="com.cjm.aop.PersonImpl"> <property name="name" value="Raymond.chen"/> <property name="age" value="30"/> </bean>
?
二、Spring AOP支持的通知類(lèi)型
???? 一)環(huán)繞通知(Around advice)
????????? 實(shí)現(xiàn)環(huán)繞通知需要實(shí)現(xiàn)org.aopalliance.intercept.MethodInterceptor接口。
?????????????? 1、PersonAroundAdvice類(lèi)的源碼
- public ? class ?PersonAroundAdvice? implements ?MethodInterceptor?{??
- ???? public ?Object?invoke(MethodInvocation?invocation)? throws ?Throwable?{??
- ????????System.out.println( "AroundAdvice:方法調(diào)用前" );??
- ??????????
- ???????? //不要忘記調(diào)用invocation的proceed方法哦 ??
- ????????Object?result?=?invocation.proceed();???
- ??????????
- ????????System.out.println( "AroundAdvice:方法調(diào)用后" );??
- ???????? return ?result;??
- ????}??
- }??
public class PersonAroundAdvice implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("AroundAdvice:方法調(diào)用前"); //不要忘記調(diào)用invocation的proceed方法哦 Object result = invocation.proceed(); System.out.println("AroundAdvice:方法調(diào)用后"); return result; } }
?
?????????????? 2、bean配置
- < bean ? id = "personAroundAdvice" ? class = "com.cjm.aop.PersonAroundAdvice" /> ??
- ??
- <!--?代理工廠bean?--> ??
- < bean ? id = "person" ? class = "org.springframework.aop.framework.ProxyFactoryBean" > ??
- ???? < property ? name = "proxyInterfaces" ? value = "com.cjm.aop.Person" /> ??
- ???? < property ? name = "target" ? ref = "personTarget" /> ??
- ???? < property ? name = "interceptorNames" > ??
- ???????? < list > ??
- ???????????? < value > personAroundAdvice </ value > ??
- ???????? </ list > ??
- ???? </ property > ??
- </ bean > ??
<bean id="personAroundAdvice" class="com.cjm.aop.PersonAroundAdvice"/> <!-- 代理工廠bean --> <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.cjm.aop.Person"/> <property name="target" ref="personTarget"/> <property name="interceptorNames"> <list> <value>personAroundAdvice</value> </list> </property> </bean>
?
?????????????? 3、測(cè)試代碼
- ApplicationContext?context?=? new ?FileSystemXmlApplicationContext( "classpath:com/cjm/aop/beans.xml" );??
- Person?p?=?(Person)context.getBean( "person" );?? //注意這里是代理工廠Bean的ID ??
- p.info();??
ApplicationContext context = new FileSystemXmlApplicationContext("classpath:com/cjm/aop/beans.xml"); Person p = (Person)context.getBean("person"); //注意這里是代理工廠Bean的ID p.info();
?
???? 二)前置通知(Before advice)
????????? 實(shí)現(xiàn)前置通知需要實(shí)現(xiàn)org.springframework.aop.MethodBeforeAdvice接口。
?????????????? 1、PersonBeforeAdvice類(lèi)的源碼
- public ? class ?PersonBeforeAdvice? implements ?MethodBeforeAdvice?{??
- ???? public ? void ?before(Method?method,?Object[]?args,?Object?target)? throws ?Throwable?{??
- ????????System.out.println( "BeforeAdvice:方法調(diào)用前" );??
- ????}??
- }??
public class PersonBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("BeforeAdvice:方法調(diào)用前"); } }
?
?????????????? 2、bean配置
- < bean ? id = "personBeforeAdvice" ? class = "com.cjm.aop.PersonBeforeAdvice" /> ??
- ??
- < bean ? id = "person" ? class = "org.springframework.aop.framework.ProxyFactoryBean" > ??
- ???? < property ? name = "proxyInterfaces" ? value = "com.cjm.aop.Person" /> ??
- ???? < property ? name = "target" ? ref = "personTarget" /> ??
- ???? < property ? name = "interceptorNames" > ??
- ???????? < list > ??
- ???????????? < value > personBeforeAdvice </ value > ??
- ???????? </ list > ??
- ???? </ property > ??
- </ bean > ??
<bean id="personBeforeAdvice" class="com.cjm.aop.PersonBeforeAdvice"/> <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.cjm.aop.Person"/> <property name="target" ref="personTarget"/> <property name="interceptorNames"> <list> <value>personBeforeAdvice</value> </list> </property> </bean>
?
???? 三)返回后通知(After Returning advice)
????????? 實(shí)現(xiàn)返回后通知需要實(shí)現(xiàn)org.springframework.aop.AfterReturningAdvice接口。
?????????????? 1、PersonAfterReturningAdvice類(lèi)的源碼
- public ? class ?PersonAfterReturningAdvice? implements ?AfterReturningAdvice?{??
- ???? public ? void ?afterReturning(Object?returnValue,?Method?method,?Object[]?args,?Object?target)? throws ?Throwable?{??
- ????????System.out.println( "AfterReturningAdvice:方法調(diào)用后" );??
- ????}??
- }??
public class PersonAfterReturningAdvice implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("AfterReturningAdvice:方法調(diào)用后"); } }
?
?????????????? 2、bean配置
- < bean ? id = "personAfterReturningAdvice" ? class = "com.cjm.aop.PersonAfterReturningAdvice" /> ??
- ??
- < bean ? id = "person" ? class = "org.springframework.aop.framework.ProxyFactoryBean" > ??
- ???? < property ? name = "proxyInterfaces" ? value = "com.cjm.aop.Person" /> ??
- ???? < property ? name = "target" ? ref = "personTarget" /> ??
- ???? < property ? name = "interceptorNames" > ??
- ???????? < list > ??
- ???????????? < value > personAfterReturningAdvice </ value > ??
- ???????? </ list > ??
- ???? </ property > ??
- </ bean > ??
<bean id="personAfterReturningAdvice" class="com.cjm.aop.PersonAfterReturningAdvice"/> <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.cjm.aop.Person"/> <property name="target" ref="personTarget"/> <property name="interceptorNames"> <list> <value>personAfterReturningAdvice</value> </list> </property> </bean>
?
?????????????? 3、以上的配置中,通知對(duì)目標(biāo)對(duì)象的所有方法都會(huì)起作用。如果需要過(guò)濾掉一部分方法,可以用正則表達(dá)式切入點(diǎn)配置器或者方法名匹配切入點(diǎn)配置器實(shí)現(xiàn)。
- <!--?通知與正則表達(dá)式切入點(diǎn)一起配置?--> ??
- <!--?Advisor等于切入點(diǎn)加通知?--> ??
- <!--?方法名匹配切入點(diǎn)配置器:org.springframework.aop.support.NameMatchMethodPointcutAdvisor?--> ??
- < bean ? id = "personPointcutAdvisor" ? class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor" > ??
- ???? < property ? name = "advice" ? ref = "personAfterReturningAdvice" /> ??
- ???? < property ? name = "patterns" > ??
- ???????? < list > ??
- ???????????? < value > .*info.* </ value > ??
- ???????? </ list > ??
- ???? </ property > ??
- </ bean > ??
- ??
- < bean ? id = "person" ? class = "org.springframework.aop.framework.ProxyFactoryBean" > ??
- ???? < property ? name = "proxyInterfaces" ? value = "com.cjm.aop.Person" /> ??
- ???? < property ? name = "target" ? ref = "personTarget" /> ??
- ???? < property ? name = "interceptorNames" > ??
- ???????? < list > ??
- ???????????? < value > personPointcutAdvisor </ value > ??
- ???????? </ list > ??
- ???? </ property > ??
- </ bean > ??
<!-- 通知與正則表達(dá)式切入點(diǎn)一起配置 --> <!-- Advisor等于切入點(diǎn)加通知 --> <!-- 方法名匹配切入點(diǎn)配置器:org.springframework.aop.support.NameMatchMethodPointcutAdvisor --> <bean id="personPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="personAfterReturningAdvice"/> <property name="patterns"> <list> <value>.*info.*</value> </list> </property> </bean> <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.cjm.aop.Person"/> <property name="target" ref="personTarget"/> <property name="interceptorNames"> <list> <value>personPointcutAdvisor</value> </list> </property> </bean>
?
???? 四)異常通知(Throws advice)
????????? 當(dāng)連接點(diǎn)拋出異常時(shí),異常通知被調(diào)用。實(shí)現(xiàn)異常通知需要實(shí)現(xiàn)org.springframework.aop.ThrowsAdvice接口,該接口不包含任何方法,但在實(shí)現(xiàn)該接口時(shí)必須實(shí)現(xiàn)如下形式的方法:
???????????????? afterThrowing([Method], [args], [target], Throwable subclass)
????????? 可以實(shí)現(xiàn)一個(gè)或多個(gè)這樣的方法。在這些方法中,只有第四個(gè)參數(shù)是必需的,前三個(gè)參數(shù)可選。
?
????????? 1、PersonThrowsAdvice類(lèi)的源碼
- public ? class ?PersonThrowsAdvice? implements ?ThrowsAdvice?{??
- ???? public ? void ?afterThrowing(FileNotFoundException?ex){??
- ????????System.out.println( "ThrowsAdvice?>>?FileNotFoundException:" ?+?ex.toString());??
- ????}??
- ??
- ???? public ? void ?afterThrowing(Object[]?args,?Exception?ex){??
- ????????System.out.println( "ThrowsAdvice?>>?Exception:" ?+?ex.getMessage());??
- ????}??
- ??
- ???? public ? void ?afterThrowing(Method?method,?Object[]?args,?Object?target,?Throwable?ex){??
- ????????System.out.println( "ThrowsAdvice?>>?Throwable:" ?+?ex.getMessage());??
- ????}??
- }??
public class PersonThrowsAdvice implements ThrowsAdvice { public void afterThrowing(FileNotFoundException ex){ System.out.println("ThrowsAdvice >> FileNotFoundException:" + ex.toString()); } public void afterThrowing(Object[] args, Exception ex){ System.out.println("ThrowsAdvice >> Exception:" + ex.getMessage()); } public void afterThrowing(Method method, Object[] args, Object target, Throwable ex){ System.out.println("ThrowsAdvice >> Throwable:" + ex.getMessage()); } }
?
??????????2、bean配置
- < bean ? id = "personThrowsAdvice" ? class = "com.cjm.aop.PersonThrowsAdvice" /> ??
- ??
- < bean ? id = "person" ? class = "org.springframework.aop.framework.ProxyFactoryBean" > ??
- ???? < property ? name = "proxyInterfaces" ? value = "com.cjm.aop.Person" /> ??
- ???? < property ? name = "target" ? ref = "personTarget" /> ??
- ???? < property ? name = "interceptorNames" > ??
- ???????? < list > ??
- ???????????? < value > personThrowsAdvice </ value > ??
- ???????? </ list > ??
- ???? </ property > ??
- </ bean > ??
<bean id="personThrowsAdvice" class="com.cjm.aop.PersonThrowsAdvice"/> <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.cjm.aop.Person"/> <property name="target" ref="personTarget"/> <property name="interceptorNames"> <list> <value>personThrowsAdvice</value> </list> </property> </bean>
?
???? 五)引入通知(Introduction advice)
?????????? 引入通知是一種特殊的通知,它能將新的成員變量、成員方法引入到目標(biāo)類(lèi)中。它不能作用于任何切入點(diǎn),因?yàn)樗蛔饔糜陬?lèi)層次,而不是方法層次。實(shí)現(xiàn)引入通知需要實(shí)現(xiàn)IntroductionAdvisor和IntroductionInterceptor接口。
?????????? 引入通知不能調(diào)用proceed方法。Advisor必須針對(duì)每個(gè)實(shí)例,并且是有狀態(tài)的。
?????????? 引入通知的效果類(lèi)似于設(shè)計(jì)模式中的訪問(wèn)者模式(Visitor Pattern)。
?
?
???????????1、Lockable接口的源碼
- public ? interface ?Lockable?{??
- ???? void ?lock();??
- ???? void ?unlock();??
- ???? boolean ?locked();??
- }??
public interface Lockable { void lock(); void unlock(); boolean locked(); }
?
?????????? 2、LockableImpl類(lèi)的源碼
- public ? class ?LockableImpl? extends ?DelegatingIntroductionInterceptor? implements ?Lockable?{??
- ???? private ? boolean ?locked;??
- ??????
- ???? public ? void ?lock()?{??
- ???????? this .locked?=? true ;??
- ????}??
- ??
- ???? public ? void ?unlock()?{??
- ???????? this .locked?=? false ;??
- ????}??
- ??
- ???? public ? boolean ?locked()?{??
- ???????? return ? this .locked;??
- ????}??
- ??
- ???? @Override ??
- ???? public ?Object?invoke(MethodInvocation?invocation)? throws ?Throwable?{??
- ???????? if ( this .locked){??
- ???????????? throw ? new ?RuntimeException( "加鎖,無(wú)法執(zhí)行" );??
- ????????}??
- ??????????
- ???????? //這里不能調(diào)用invocation的proceed方法 ??
- ???????? //通常不需要改寫(xiě)invoke方法,直接調(diào)用父類(lèi)的該方法即可 ??
- ???????? return ? super .invoke(invocation);??
- ????}??
- }??
public class LockableImpl extends DelegatingIntroductionInterceptor implements Lockable { private boolean locked; public void lock() { this.locked = true; } public void unlock() { this.locked = false; } public boolean locked() { return this.locked; } @Override public Object invoke(MethodInvocation invocation) throws Throwable { if(this.locked){ throw new RuntimeException("加鎖,無(wú)法執(zhí)行"); } //這里不能調(diào)用invocation的proceed方法 //通常不需要改寫(xiě)invoke方法,直接調(diào)用父類(lèi)的該方法即可 return super.invoke(invocation); } }
?
?????????? 3、PersonIntroductionAdvice類(lèi)的源碼
- public ? class ?PersonIntroductionAdvice? extends ?DefaultIntroductionAdvisor?{??
- ???? public ?PersonIntroductionAdvice(){??
- ???????? super ( new ?LockableImpl(),?Lockable. class );??
- ????}??
- }??
public class PersonIntroductionAdvice extends DefaultIntroductionAdvisor { public PersonIntroductionAdvice(){ super(new LockableImpl(), Lockable.class); } }
?
?????????? 4、bean配置
- <!--?Advice必須針對(duì)每個(gè)實(shí)例,所以scope要設(shè)為prototype?--> ??
- < bean ? id = "personIntroductionAdvice" ? class = "com.cjm.aop.introduction.PersonIntroductionAdvice" ? scope = "prototype" /> ??
- ??
- < bean ? id = "person" ? class = "org.springframework.aop.framework.ProxyFactoryBean" > ??
- ???? < property ? name = "proxyInterfaces" ? value = "com.cjm.aop.Person" /> ??
- ???? < property ? name = "target" ? ref = "personTarget" /> ??
- ???? < property ? name = "interceptorNames" > ??
- ???????? < list > ??
- ???????????? < value > personIntroductionAdvice </ value > ??
- ???????? </ list > ??
- ???? </ property > ??
- </ bean > ??
<!-- Advice必須針對(duì)每個(gè)實(shí)例,所以scope要設(shè)為prototype --> <bean id="personIntroductionAdvice" class="com.cjm.aop.introduction.PersonIntroductionAdvice" scope="prototype"/> <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.cjm.aop.Person"/> <property name="target" ref="personTarget"/> <property name="interceptorNames"> <list> <value>personIntroductionAdvice</value> </list> </property> </bean>
?
?????????? 5、測(cè)試代碼
- ApplicationContext?context?=? new ?FileSystemXmlApplicationContext( "classpath:com/cjm/aop/beans.xml" );??
- ??
- //獲得目標(biāo)bean的代理bean ??
- Person?p?=?(Person)context.getBean( "person" );??
- ??
- //執(zhí)行代理bean的方法,此時(shí)并未調(diào)用lock方法,可以執(zhí)行 ??
- p.info();??
- ??
- Lockable?lockable?=?(Lockable)p;??
- lockable.lock();??
- ??
- //目標(biāo)bean已被鎖定,此處將拋出異常 ??
- p.info();??
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
