轉載自: http://chenjumin.iteye.com/blog/364948
?
一、基礎接口和類
???? 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類的源碼
- 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的配置
- <!--?目標對象?--> ??
- < bean ? id = "personTarget" ? class = "com.cjm.aop.PersonImpl" > ??
- ???? < property ? name = "name" ? value = "Raymond.chen" /> ??
- ???? < property ? name = "age" ? value = "30" /> ??
- </ bean > ??
<!-- 目標對象 --> <bean id="personTarget" class="com.cjm.aop.PersonImpl"> <property name="name" value="Raymond.chen"/> <property name="age" value="30"/> </bean>
?
二、Spring AOP支持的通知類型
???? 一)環繞通知(Around advice)
????????? 實現環繞通知需要實現org.aopalliance.intercept.MethodInterceptor接口。
?????????????? 1、PersonAroundAdvice類的源碼
- public ? class ?PersonAroundAdvice? implements ?MethodInterceptor?{??
- ???? public ?Object?invoke(MethodInvocation?invocation)? throws ?Throwable?{??
- ????????System.out.println( "AroundAdvice:方法調用前" );??
- ??????????
- ???????? //不要忘記調用invocation的proceed方法哦 ??
- ????????Object?result?=?invocation.proceed();???
- ??????????
- ????????System.out.println( "AroundAdvice:方法調用后" );??
- ???????? return ?result;??
- ????}??
- }??
public class PersonAroundAdvice implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("AroundAdvice:方法調用前"); //不要忘記調用invocation的proceed方法哦 Object result = invocation.proceed(); System.out.println("AroundAdvice:方法調用后"); 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、測試代碼
- 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)
????????? 實現前置通知需要實現org.springframework.aop.MethodBeforeAdvice接口。
?????????????? 1、PersonBeforeAdvice類的源碼
- public ? class ?PersonBeforeAdvice? implements ?MethodBeforeAdvice?{??
- ???? public ? void ?before(Method?method,?Object[]?args,?Object?target)? throws ?Throwable?{??
- ????????System.out.println( "BeforeAdvice:方法調用前" );??
- ????}??
- }??
public class PersonBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("BeforeAdvice:方法調用前"); } }
?
?????????????? 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)
????????? 實現返回后通知需要實現org.springframework.aop.AfterReturningAdvice接口。
?????????????? 1、PersonAfterReturningAdvice類的源碼
- public ? class ?PersonAfterReturningAdvice? implements ?AfterReturningAdvice?{??
- ???? public ? void ?afterReturning(Object?returnValue,?Method?method,?Object[]?args,?Object?target)? throws ?Throwable?{??
- ????????System.out.println( "AfterReturningAdvice:方法調用后" );??
- ????}??
- }??
public class PersonAfterReturningAdvice implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("AfterReturningAdvice:方法調用后"); } }
?
?????????????? 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、以上的配置中,通知對目標對象的所有方法都會起作用。如果需要過濾掉一部分方法,可以用正則表達式切入點配置器或者方法名匹配切入點配置器實現。
- <!--?通知與正則表達式切入點一起配置?--> ??
- <!--?Advisor等于切入點加通知?--> ??
- <!--?方法名匹配切入點配置器: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 > ??
<!-- 通知與正則表達式切入點一起配置 --> <!-- Advisor等于切入點加通知 --> <!-- 方法名匹配切入點配置器: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)
????????? 當連接點拋出異常時,異常通知被調用。實現異常通知需要實現org.springframework.aop.ThrowsAdvice接口,該接口不包含任何方法,但在實現該接口時必須實現如下形式的方法:
???????????????? afterThrowing([Method], [args], [target], Throwable subclass)
????????? 可以實現一個或多個這樣的方法。在這些方法中,只有第四個參數是必需的,前三個參數可選。
?
????????? 1、PersonThrowsAdvice類的源碼
- 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)
?????????? 引入通知是一種特殊的通知,它能將新的成員變量、成員方法引入到目標類中。它不能作用于任何切入點,因為它只作用于類層次,而不是方法層次。實現引入通知需要實現IntroductionAdvisor和IntroductionInterceptor接口。
?????????? 引入通知不能調用proceed方法。Advisor必須針對每個實例,并且是有狀態的。
?????????? 引入通知的效果類似于設計模式中的訪問者模式(Visitor Pattern)。
?
?
???????????1、Lockable接口的源碼
- public ? interface ?Lockable?{??
- ???? void ?lock();??
- ???? void ?unlock();??
- ???? boolean ?locked();??
- }??
public interface Lockable { void lock(); void unlock(); boolean locked(); }
?
?????????? 2、LockableImpl類的源碼
- 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( "加鎖,無法執行" );??
- ????????}??
- ??????????
- ???????? //這里不能調用invocation的proceed方法 ??
- ???????? //通常不需要改寫invoke方法,直接調用父類的該方法即可 ??
- ???????? 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("加鎖,無法執行"); } //這里不能調用invocation的proceed方法 //通常不需要改寫invoke方法,直接調用父類的該方法即可 return super.invoke(invocation); } }
?
?????????? 3、PersonIntroductionAdvice類的源碼
- 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必須針對每個實例,所以scope要設為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必須針對每個實例,所以scope要設為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、測試代碼
- ApplicationContext?context?=? new ?FileSystemXmlApplicationContext( "classpath:com/cjm/aop/beans.xml" );??
- ??
- //獲得目標bean的代理bean ??
- Person?p?=?(Person)context.getBean( "person" );??
- ??
- //執行代理bean的方法,此時并未調用lock方法,可以執行 ??
- p.info();??
- ??
- Lockable?lockable?=?(Lockable)p;??
- lockable.lock();??
- ??
- //目標bean已被鎖定,此處將拋出異常 ??
- p.info();??
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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