在Spring1.2或之前的版本中,實現(xiàn)AOP的傳統(tǒng)方式就是通過實現(xiàn)Spring的AOP API來定義Advice,并設(shè)置代理對象。Spring根據(jù)Adivce加入到業(yè)務(wù)流程的時機的不同,提供了四種不同的Advice:Before Advice、After Advice、Around Advice、Throw Advice。
1、Before Advice
顧名思義,Before Advice會在目標(biāo)對象的方法執(zhí)行之前被調(diào)用,您可以通過實現(xiàn)org.springframework.aop.MethodBeforeAdvice接口來實現(xiàn)Before Advice的邏輯,接口定義如下:
java 代碼
1. package org.springframework.aop;
2.
3. public interface MethodBeforeAdvice extends BeforeAdvice {
4. void before(Method method, Object[] args, Object target) throws Throwable;
5. }
其中BeforeAdvice繼承自Adivce接口,這兩者都是標(biāo)簽接口,并沒有定義任何具體的方法。before方法會在目標(biāo)對象的指定方法執(zhí)行之前被執(zhí)行,在before方法種,你可以取得指定方法的Method實例、參數(shù)列表和目標(biāo)對象,在before方法執(zhí)行完后,目標(biāo)對象上的方法將會執(zhí)行,除非在before方法種拋出異常。
下面通過例子來說明Before Advice的使用方法。首先定義目標(biāo)對象所要實現(xiàn)的接口:
java 代碼
1. package com.savage.aop
2.
3. public interface MessageSender {
4. void send(String message);
5. }
接著實現(xiàn)MessageSender接口:
java 代碼
1. package com.savage.aop;
2.
3. public class HttpMessageSender implements MessageSender {
4. public void send(String message) {
5. System.out.println("Send Message[" + message + "] by http.");
6. }
7. }
OK,我們的業(yè)務(wù)代碼實現(xiàn)完了,現(xiàn)在如果要在不改變我們的業(yè)務(wù)代碼的前提下,在執(zhí)行業(yè)務(wù)代碼前要記錄一些日志,這時就可以通過實現(xiàn)MethodBeforeAdvice接口來實現(xiàn),如:
java 代碼
1. package com.savage.aop;
2.
3. import java.lang.reflect.Method;
4.
5. import org.springframework.aop.framework.MethodBeforeAdvice;
6.
7. public class LogBeforeAdvice implements MethodAdvice {
8. public void before(Method method, Object[] args, Object target) throws Throwable {
9. System.out.println("Log before " + method + " by LogBeforeAdvice.");
10. }
11. }
然后再在XML進行如下定義:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
10.
11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
12. <property name="proxyInterfaces" value="com.savage.aop.MessageSender"/>
13. <property name="target" ref="messageSenderImpl"/>
14. <property name="interceptorNames">
15. <list>
16. <value>logBeforeAdvice</value>
17. </list>
18. </property>
19. </bean>
20. </beans>
這樣我們就為MessageSender對象指定了Before Advice對象。在這里,我們分別定義了一個MessageSender對象(messageSenderImpl)和一個Before Advice對象(logBeforeAdvice),并定義了一個 org.springframework.aop.framework.ProxyFactoryBean對象(messageSender),F(xiàn)actoryBean或ApplicationContext將使用ProxyFactoryBean來建立代理對象,在這里就是messageSenderImpl建立代理對象。在ProxyFactoryBean的定義中,proxyInterfaces屬性指定了要代理的接口;target指定了要建立代理的目標(biāo)對象;interceptorNames則指定了應(yīng)用與指定接口上的Advices對象列表,spring將根據(jù)列表中定義的順序在執(zhí)行目標(biāo)對象的方法前、后執(zhí)行Advice中定義的方法。
現(xiàn)在我們寫一個程序來驗證下:
java 代碼
1. package com.savage.aop;
2.
3. import org.springframework.context.ApplicationContext;
4. import org.springframework.context.support.ClassPathXmlApplication;
5.
6. public class AdviceDemo {
7. public void main(String[] args) {
8. ApplicationContext context = new ClassPathXmlApplicationContext("beans-config.xml");
9. MessageSender sender = (MessageSender)context.getBean("messageSender");
10. sender.send("message");
11. }
12. }
執(zhí)行結(jié)果:
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogBeforeAdvice.
Send Message[message] by http.
正如你所看到的,在執(zhí)行MessageSender的send方法前先執(zhí)行了LogBeforeAdvice的方法!在這個例子中,記錄日志的代碼并沒有橫切到我們的業(yè)務(wù)代碼中,LogBeforeAdvice和HttpMessageSender彼此不知道對方的存在,而且我們的應(yīng)用程序AdviceDemo對LogBeforeAdvice的存在也是一無所知。假如有一天我們的應(yīng)用程序不需要再業(yè)務(wù)代碼執(zhí)行前記錄日志了,只需要修改XML文件中的定義,而不用更改AdviceDemo的代碼:
xml 代碼
1. <bean id="messageSender" class="com.savage.aop.HttpMessageSender">bean>
2、After Advice
After Advice會在目標(biāo)對象的方法執(zhí)行完后執(zhí)行,你可以通過實現(xiàn)org.springframework.aop.AfterReturingAdvice接口來實現(xiàn)After Advice的邏輯,AfterReturingAdvice接口定義如下:
java 代碼
1. package org.springframework.aop;
2.
3. public interface AfterReturningAdvice {
4. void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
5. }
在afterReturning方法中,你可以獲得目標(biāo)方法執(zhí)行后的返回值、目標(biāo)方法對象、目標(biāo)方法的參數(shù)以及目標(biāo)對象。
繼續(xù)以上面的例子為例,如果要在MessageSender的send方法執(zhí)行完后,要再記錄日志,那么我們可以先實現(xiàn)AfterReturningAdvice接口:
java 代碼
1. package com.savage.aop;
2.
3. import org.springframework.aop;
4.
5. public LogAfterAdvice implements AfterReturningAdvice {
6. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
7. System.out.println("Log after " + method + " by LogAfterAdvice.");
8. }
9. }
然后在XML文件中指定LogAfterAdvice的實例:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
10.
11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
12. <property name="proxyInterfaces" value="com.savage.aop.MessageSender"/>
13. <property name="target" ref="messageSenderImpl"/>
14. <property name="interceptorNames">
15. <list>
16. <value>logAfterAdvice</value>
17. </list>
18. </property>
19. </bean>
20. </beans>
在前面Before Advice的基礎(chǔ)上,我們?yōu)镸essageSender再指定了一個LogAfterAdvice的服務(wù)。運行前面的AdviceDemo,結(jié)果如下:
Send Message[message] by http.
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAfterAdvice.
3、Around Advice
在上面的LogAfterAdvice例子中,我們通過指定BeforeAdvice和AfterReturingAdvice,在MessageSender的send方法前后執(zhí)行額外的業(yè)務(wù)。實際上,如果需要在業(yè)務(wù)代碼執(zhí)行前后增加額外的服務(wù),你可以直接通過實現(xiàn)org.aopalliance.intercept.MethodInterceptor接口來達到這一目的,MethodInterceptor定義如下:
java 代碼
1. package org.aopalliance.intercept;
2.
3. public interface MethodInterceptor {
4. public Object invoke(MethodInvocation methodInvocation) throws Throwable;
5. }
例如:
java 代碼
1. package com.savage.aop;
2.
3. import org.aopalliance.intercept.MethodInterceptor;
4. import org.aopalliance.intercept.MethodInvocation;
5.
6. public class LogAdvice implements MethodInterceptor {
7. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
8. System.out.println("Log before " + methodInvocation.getMethod() + " by LogAdvice.");
9. Object retValue = methodInvocation.proceed();
10. System.out.println("Log after " + methodInvocation.getMethod() + " by LogAdvice.");
11. return retValue;
12. }
13. }
正如上面所示,在MethodInterceptor中你得自行決定是否調(diào)用MethodInvocation的proceed()方法來執(zhí)行目標(biāo)對象上的方法,proceed()方法在執(zhí)行完后會返回目標(biāo)對象上方法的執(zhí)行結(jié)果。
MethodInterceptor在XML文件中的定義如下:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logAdvice" class="com.savage.aop.LogAdvice"></bean>
10.
11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
12. <property id="proxyInterfaces" value="com.savage.aop.MessageSender"/>
13. <property id="target" ref="messageSenderImpl"/>
14. <property id="interceptorNames">
15. <list>
16. <value>logAdvice</value>
17. </list>
18. </property>
19. </bean>
20. </beans>
Spring在真正執(zhí)行目標(biāo)對象的方法前,會執(zhí)行interceptorNames中執(zhí)行的Advice,每個Advice在執(zhí)行完自己的業(yè)務(wù)后,會調(diào)用MethodInvocation的proceed()方法,將執(zhí)行的主動權(quán)移交給下一個Advice,直到?jīng)]有下一個Advice為止,在執(zhí)行完目標(biāo)對象的方法后,Spring會再以相反的順序一層層的返回。例如:
xml 代碼
1. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
2. <property id="proxyInterfaces" value="com.savage.aop.MessageSender"/>
3. <property id="target" ref="messageSenderImpl"/>
4. <property id="interceptorNames">
5. <list>
6. <value>logBeforeAdvice</value>
7. <value>logAdvice</value>
8. <value>logAfterAdvice</value>
9. </list>
10. </property>
11. </bean>
象上面這個例子,logBeforeAdvice先會被執(zhí)行,然后執(zhí)行l(wèi)ogAdvice,接著執(zhí)行l(wèi)ogAfterAdvice,最后又返回到了logAdvice。
現(xiàn)在我們把LogAdvice作一下簡單的修改,增加一個id屬性,用以在后面查看Advice的調(diào)用順序:
java 代碼
1. package com.savage.aop;
2.
3. import org.aopalliance.intercept.MethodInterceptor;
4. import org.aopalliance.intercept.MethodInvocation;
5.
6. public class LogAdvice implements MethodInterceptor {
7. private static int INSTANCE_NUM = 0;
8.
9. private int id;
10.
11. public LogAdvice() {
12. id = ++INSTANCE_NUM;
13. }
14.
15. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
16. System.out.println("Log before " + methodInvocation.getMethod() + " by LogAdvice[" + id + "].");
17. Object retValue = methodInvocation.proceed();
18. System.out.println("Log after " + methodInvocation.getMethod() + " by LogAdvice[" + id + "].");
19. return retValue;
20. }
21. }
同時把XML中的定義改為:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
10. <bean id="logAfterAdvice" class="com.savage.aop.LogAfterAdvice"></bean>
11. <bean id="logAdvice1" class="com.savage.aop.LogAdvice"></bean>
12. <bean id="logAdvice2" class="com.savage.aop.LogAdvice"></bean>
13.
14. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
15. <property id="proxyInterfaces" value="com.savage.aop.MessageSender"/>
16. <property id="target" ref="messageSenderImpl"/>
17. <property id="interceptorNames">
18. <list>
19. <value>logBeforeAdvice</value>
20. <value>logAdvice1</value>
21. <value>logAfterAdvice</value>
22. <value>logAdvice2</value>
23. </list>
24. </property>
25. </bean>
26. </beans>
現(xiàn)在再執(zhí)行AdviceDemo,得到如下結(jié)果:
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogBeforeAdvice.
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[1].
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[2].
Send Message[message] by http.
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[2].
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAfterAdvice.
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[1].
4、Throw Advice
如果想要在異常發(fā)生時執(zhí)行某些業(yè)務(wù),你可以通過實現(xiàn)org.springframework.aop.ThrowsAdvice接口,這是一個標(biāo)簽接口,沒有定義任何方法,你可以在當(dāng)中為每個你需要處理的異常類定義afterThrowing方法,當(dāng)程序出現(xiàn)異常時,spring會根據(jù)異常的類型調(diào)用對應(yīng)的afterThrowing方法。AfterThrowing的格式如下:
java 代碼
1. afterThrowing([Method],[args],[target],subClassOfThrowable);
方括號[]中的參數(shù)為可選項,但方法中必須有subClassOfThrowable,且必須是Throwable的子類。
Spring在調(diào)用完afterThrowing方法后,原先的異常會繼續(xù)在程序中傳播,如果象要終止程序?qū)Ξ惓5奶幚恚荒茉赼fterThrowing方法中拋出其他異常。
1、Before Advice
顧名思義,Before Advice會在目標(biāo)對象的方法執(zhí)行之前被調(diào)用,您可以通過實現(xiàn)org.springframework.aop.MethodBeforeAdvice接口來實現(xiàn)Before Advice的邏輯,接口定義如下:
java 代碼
1. package org.springframework.aop;
2.
3. public interface MethodBeforeAdvice extends BeforeAdvice {
4. void before(Method method, Object[] args, Object target) throws Throwable;
5. }
其中BeforeAdvice繼承自Adivce接口,這兩者都是標(biāo)簽接口,并沒有定義任何具體的方法。before方法會在目標(biāo)對象的指定方法執(zhí)行之前被執(zhí)行,在before方法種,你可以取得指定方法的Method實例、參數(shù)列表和目標(biāo)對象,在before方法執(zhí)行完后,目標(biāo)對象上的方法將會執(zhí)行,除非在before方法種拋出異常。
下面通過例子來說明Before Advice的使用方法。首先定義目標(biāo)對象所要實現(xiàn)的接口:
java 代碼
1. package com.savage.aop
2.
3. public interface MessageSender {
4. void send(String message);
5. }
接著實現(xiàn)MessageSender接口:
java 代碼
1. package com.savage.aop;
2.
3. public class HttpMessageSender implements MessageSender {
4. public void send(String message) {
5. System.out.println("Send Message[" + message + "] by http.");
6. }
7. }
OK,我們的業(yè)務(wù)代碼實現(xiàn)完了,現(xiàn)在如果要在不改變我們的業(yè)務(wù)代碼的前提下,在執(zhí)行業(yè)務(wù)代碼前要記錄一些日志,這時就可以通過實現(xiàn)MethodBeforeAdvice接口來實現(xiàn),如:
java 代碼
1. package com.savage.aop;
2.
3. import java.lang.reflect.Method;
4.
5. import org.springframework.aop.framework.MethodBeforeAdvice;
6.
7. public class LogBeforeAdvice implements MethodAdvice {
8. public void before(Method method, Object[] args, Object target) throws Throwable {
9. System.out.println("Log before " + method + " by LogBeforeAdvice.");
10. }
11. }
然后再在XML進行如下定義:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
10.
11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
12. <property name="proxyInterfaces" value="com.savage.aop.MessageSender"/>
13. <property name="target" ref="messageSenderImpl"/>
14. <property name="interceptorNames">
15. <list>
16. <value>logBeforeAdvice</value>
17. </list>
18. </property>
19. </bean>
20. </beans>
這樣我們就為MessageSender對象指定了Before Advice對象。在這里,我們分別定義了一個MessageSender對象(messageSenderImpl)和一個Before Advice對象(logBeforeAdvice),并定義了一個 org.springframework.aop.framework.ProxyFactoryBean對象(messageSender),F(xiàn)actoryBean或ApplicationContext將使用ProxyFactoryBean來建立代理對象,在這里就是messageSenderImpl建立代理對象。在ProxyFactoryBean的定義中,proxyInterfaces屬性指定了要代理的接口;target指定了要建立代理的目標(biāo)對象;interceptorNames則指定了應(yīng)用與指定接口上的Advices對象列表,spring將根據(jù)列表中定義的順序在執(zhí)行目標(biāo)對象的方法前、后執(zhí)行Advice中定義的方法。
現(xiàn)在我們寫一個程序來驗證下:
java 代碼
1. package com.savage.aop;
2.
3. import org.springframework.context.ApplicationContext;
4. import org.springframework.context.support.ClassPathXmlApplication;
5.
6. public class AdviceDemo {
7. public void main(String[] args) {
8. ApplicationContext context = new ClassPathXmlApplicationContext("beans-config.xml");
9. MessageSender sender = (MessageSender)context.getBean("messageSender");
10. sender.send("message");
11. }
12. }
執(zhí)行結(jié)果:
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogBeforeAdvice.
Send Message[message] by http.
正如你所看到的,在執(zhí)行MessageSender的send方法前先執(zhí)行了LogBeforeAdvice的方法!在這個例子中,記錄日志的代碼并沒有橫切到我們的業(yè)務(wù)代碼中,LogBeforeAdvice和HttpMessageSender彼此不知道對方的存在,而且我們的應(yīng)用程序AdviceDemo對LogBeforeAdvice的存在也是一無所知。假如有一天我們的應(yīng)用程序不需要再業(yè)務(wù)代碼執(zhí)行前記錄日志了,只需要修改XML文件中的定義,而不用更改AdviceDemo的代碼:
xml 代碼
1. <bean id="messageSender" class="com.savage.aop.HttpMessageSender">bean>
2、After Advice
After Advice會在目標(biāo)對象的方法執(zhí)行完后執(zhí)行,你可以通過實現(xiàn)org.springframework.aop.AfterReturingAdvice接口來實現(xiàn)After Advice的邏輯,AfterReturingAdvice接口定義如下:
java 代碼
1. package org.springframework.aop;
2.
3. public interface AfterReturningAdvice {
4. void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
5. }
在afterReturning方法中,你可以獲得目標(biāo)方法執(zhí)行后的返回值、目標(biāo)方法對象、目標(biāo)方法的參數(shù)以及目標(biāo)對象。
繼續(xù)以上面的例子為例,如果要在MessageSender的send方法執(zhí)行完后,要再記錄日志,那么我們可以先實現(xiàn)AfterReturningAdvice接口:
java 代碼
1. package com.savage.aop;
2.
3. import org.springframework.aop;
4.
5. public LogAfterAdvice implements AfterReturningAdvice {
6. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
7. System.out.println("Log after " + method + " by LogAfterAdvice.");
8. }
9. }
然后在XML文件中指定LogAfterAdvice的實例:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
10.
11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
12. <property name="proxyInterfaces" value="com.savage.aop.MessageSender"/>
13. <property name="target" ref="messageSenderImpl"/>
14. <property name="interceptorNames">
15. <list>
16. <value>logAfterAdvice</value>
17. </list>
18. </property>
19. </bean>
20. </beans>
在前面Before Advice的基礎(chǔ)上,我們?yōu)镸essageSender再指定了一個LogAfterAdvice的服務(wù)。運行前面的AdviceDemo,結(jié)果如下:
Send Message[message] by http.
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAfterAdvice.
3、Around Advice
在上面的LogAfterAdvice例子中,我們通過指定BeforeAdvice和AfterReturingAdvice,在MessageSender的send方法前后執(zhí)行額外的業(yè)務(wù)。實際上,如果需要在業(yè)務(wù)代碼執(zhí)行前后增加額外的服務(wù),你可以直接通過實現(xiàn)org.aopalliance.intercept.MethodInterceptor接口來達到這一目的,MethodInterceptor定義如下:
java 代碼
1. package org.aopalliance.intercept;
2.
3. public interface MethodInterceptor {
4. public Object invoke(MethodInvocation methodInvocation) throws Throwable;
5. }
例如:
java 代碼
1. package com.savage.aop;
2.
3. import org.aopalliance.intercept.MethodInterceptor;
4. import org.aopalliance.intercept.MethodInvocation;
5.
6. public class LogAdvice implements MethodInterceptor {
7. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
8. System.out.println("Log before " + methodInvocation.getMethod() + " by LogAdvice.");
9. Object retValue = methodInvocation.proceed();
10. System.out.println("Log after " + methodInvocation.getMethod() + " by LogAdvice.");
11. return retValue;
12. }
13. }
正如上面所示,在MethodInterceptor中你得自行決定是否調(diào)用MethodInvocation的proceed()方法來執(zhí)行目標(biāo)對象上的方法,proceed()方法在執(zhí)行完后會返回目標(biāo)對象上方法的執(zhí)行結(jié)果。
MethodInterceptor在XML文件中的定義如下:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logAdvice" class="com.savage.aop.LogAdvice"></bean>
10.
11. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
12. <property id="proxyInterfaces" value="com.savage.aop.MessageSender"/>
13. <property id="target" ref="messageSenderImpl"/>
14. <property id="interceptorNames">
15. <list>
16. <value>logAdvice</value>
17. </list>
18. </property>
19. </bean>
20. </beans>
Spring在真正執(zhí)行目標(biāo)對象的方法前,會執(zhí)行interceptorNames中執(zhí)行的Advice,每個Advice在執(zhí)行完自己的業(yè)務(wù)后,會調(diào)用MethodInvocation的proceed()方法,將執(zhí)行的主動權(quán)移交給下一個Advice,直到?jīng)]有下一個Advice為止,在執(zhí)行完目標(biāo)對象的方法后,Spring會再以相反的順序一層層的返回。例如:
xml 代碼
1. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
2. <property id="proxyInterfaces" value="com.savage.aop.MessageSender"/>
3. <property id="target" ref="messageSenderImpl"/>
4. <property id="interceptorNames">
5. <list>
6. <value>logBeforeAdvice</value>
7. <value>logAdvice</value>
8. <value>logAfterAdvice</value>
9. </list>
10. </property>
11. </bean>
象上面這個例子,logBeforeAdvice先會被執(zhí)行,然后執(zhí)行l(wèi)ogAdvice,接著執(zhí)行l(wèi)ogAfterAdvice,最后又返回到了logAdvice。
現(xiàn)在我們把LogAdvice作一下簡單的修改,增加一個id屬性,用以在后面查看Advice的調(diào)用順序:
java 代碼
1. package com.savage.aop;
2.
3. import org.aopalliance.intercept.MethodInterceptor;
4. import org.aopalliance.intercept.MethodInvocation;
5.
6. public class LogAdvice implements MethodInterceptor {
7. private static int INSTANCE_NUM = 0;
8.
9. private int id;
10.
11. public LogAdvice() {
12. id = ++INSTANCE_NUM;
13. }
14.
15. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
16. System.out.println("Log before " + methodInvocation.getMethod() + " by LogAdvice[" + id + "].");
17. Object retValue = methodInvocation.proceed();
18. System.out.println("Log after " + methodInvocation.getMethod() + " by LogAdvice[" + id + "].");
19. return retValue;
20. }
21. }
同時把XML中的定義改為:
xml 代碼
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://www.springframework.org/schema/beans
5. http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6.
7. <bean id="messageSenderImpl" class="com.savage.aop.HttpMessageSender"></bean>
8.
9. <bean id="logBeforeAdvice" class="com.savage.aop.LogBeforeAdvice"></bean>
10. <bean id="logAfterAdvice" class="com.savage.aop.LogAfterAdvice"></bean>
11. <bean id="logAdvice1" class="com.savage.aop.LogAdvice"></bean>
12. <bean id="logAdvice2" class="com.savage.aop.LogAdvice"></bean>
13.
14. <bean id="messageSender" class="org.springframework.aop.framework.ProxyFactoryBean">
15. <property id="proxyInterfaces" value="com.savage.aop.MessageSender"/>
16. <property id="target" ref="messageSenderImpl"/>
17. <property id="interceptorNames">
18. <list>
19. <value>logBeforeAdvice</value>
20. <value>logAdvice1</value>
21. <value>logAfterAdvice</value>
22. <value>logAdvice2</value>
23. </list>
24. </property>
25. </bean>
26. </beans>
現(xiàn)在再執(zhí)行AdviceDemo,得到如下結(jié)果:
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogBeforeAdvice.
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[1].
Log before public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[2].
Send Message[message] by http.
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[2].
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAfterAdvice.
Log after public abstract void com.savage.simplespring.bean.MessageSender.send(java.lang.String) by LogAdvice[1].
4、Throw Advice
如果想要在異常發(fā)生時執(zhí)行某些業(yè)務(wù),你可以通過實現(xiàn)org.springframework.aop.ThrowsAdvice接口,這是一個標(biāo)簽接口,沒有定義任何方法,你可以在當(dāng)中為每個你需要處理的異常類定義afterThrowing方法,當(dāng)程序出現(xiàn)異常時,spring會根據(jù)異常的類型調(diào)用對應(yīng)的afterThrowing方法。AfterThrowing的格式如下:
java 代碼
1. afterThrowing([Method],[args],[target],subClassOfThrowable);
方括號[]中的參數(shù)為可選項,但方法中必須有subClassOfThrowable,且必須是Throwable的子類。
Spring在調(diào)用完afterThrowing方法后,原先的異常會繼續(xù)在程序中傳播,如果象要終止程序?qū)Ξ惓5奶幚恚荒茉赼fterThrowing方法中拋出其他異常。