spring aop 环绕通知around和其他通知的区别
前言:
?????spring?的環繞通知和前置通知,后置通知有著很大的區別,主要有兩個重要的區別:
1)?目標方法的調用由環繞通知決定,即你可以決定是否調用目標方法,而前置和后置通知???是不能決定的,他們只是在方法的調用前后執行通知而已,即目標方法肯定是要執行的。
2)??環繞通知可以控制返回對象,即你可以返回一個與目標對象完全不同的返回值,雖然這很危險,但是你卻可以辦到。而后置方法是無法辦到的,因為他是在目標方法返回值后調用
?? 這里是經過我自己測試的過的例子,使用面向切面來處理一些問公共的問題,比如,權限管理,事務的委托
下面的例子就是使用環繞通知,當程序發生異常時,重復提交請求,重復的次數是可以設定的
??? 當我們開發企業級應用時,通常會想要從幾個切面來引用模塊化的應用和特定操作的集合,下面是一個典型的通用切面,看起來可能像下面這樣(這也是Spring文檔里的)
?
package test.prefer.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SystemArchitecture {
? /**
?? * A join point is in the web layer if the method is defined
?? * in a type in the com.xyz.someapp.web package or any sub-package
?? * under that.
?? */
? @Pointcut("within(com.xyz.someapp.web..*)")
? public void inWebLayer() {}
? /**
?? * A join point is in the service layer if the method is defined
?? * in a type in the com.xyz.someapp.service package or any sub-package
?? * under that.
?? */
? @Pointcut("within(com.xyz.someapp.service..*)")
? public void inServiceLayer(){}
? /**
?? * A join point is in the data access layer if the method is defined
?? * in a type in the com.xyz.someapp.dao package or any sub-package
?? * under that.
?? */
? @Pointcut("within(com.xyz.someapp.dao..*)")
? public void inDataAccessLayer(){}
? /**
?? * A business service is the execution of any method defined on a service
?? * interface. This definition assumes that interfaces are placed in the
?? * "service" package, and that implementation types are in sub-packages.
?? *?
?? * If you group service interfaces by functional area (for example,?
?? * in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
?? * the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
?? * could be used instead.
?? *
?? * Alternatively, you can write the expression using the 'bean'
?? * PCD, like so "bean(*Service)". (This assumes that you have
?? * named your Spring service beans in a consistent fashion.)
?? */
? @Pointcut("execution(* test.prefer.aspect.*.*(..))")
? public void businessService(){}
??
? /**
?? * A data access operation is the execution of any method defined on a?
?? * dao interface. This definition assumes that interfaces are placed in the
?? * "dao" package, and that implementation types are in sub-packages.
?? */
? @Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
? public void dataAccessOperation(){}
}
?
?一、定義自己的一個切面
/*
*文件名:ConcurrentOperationExecutor.Java
*描述:<描述>
*修改人:Administrator
*/
package test.prefer.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
/**
?* @author?
?*@date?2010-6-1
?*/
@Aspect
public class ConcurrentOperationExecutor implements Ordered {
???
?? private static final int DEFAULT_MAX_RETRIES = 2;
?? private int maxRetries = DEFAULT_MAX_RETRIES;
?? private int order = 1;
?? public void setMaxRetries(int maxRetries) {
????? this.maxRetries = maxRetries;
?? }
???
?? public int getOrder(){
????? return this.order;
?? }
?? public void setOrder(int order){
????? this.order = order;
?? }
???
?? @Around("test.prefer.aspect.SystemArchitecture.businessService()")
?? public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {?
??? //環繞通知處理方法
????? int numAttempts = 0;
????? Exception lockFailureException;
????? do {
???????? numAttempts++;
???????? try {?
??????? ? System.out.println("環繞通知方法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............");
??????????? return pjp.proceed();
???????? }
???????? catch(Exception ex) {
??????????? lockFailureException = ex;
???????? }
????? }
????? while(numAttempts <= this.maxRetries);
????? throw lockFailureException;
?? }
}
?
說明:
??? 請注意切面實現了?Ordered?接口,這樣我們就可以把切面的優先級設定為高于事務通知 (我們每次重試的時候都想要在一個全新的事務中進行)。maxRetries和order?屬性都可以在Spring中配置。主要的動作在doConcurrentOperation這個環繞通知方法中發生。 請注意這個時候我們所有的businessService()方法都會使用這個重試策略。 我們首先會嘗試處理,如果得到一個Exception異常, 我們僅僅重試直到耗盡所有預設的重試次數(spring開發文檔)
?
二、在配置文件里配置這個切面
<aop:aspectj-autoproxy/>
<bean id="concurrentOperationExecutor"
? class="test.prefer.aspect.ConcurrentOperationExecutor">
???? <property name="maxRetries" value="3"/>
???? <property name="order" value="100"/>??
</bean>
?
好了,下面我們就試一下效果吧
?
三、測試效果
??? 1)新建一個測試的bean: MyTestAspect,代碼如下:
package test.prefer.aspect;
/**
?* 這是一個切面類
?*/
import org.aspectj.lang.annotation.Aspect;
public class MyTestAspect {
?int k=0;
?public void test(String args) throws Exception{
??System.out.println("這里是[ 目標 ]方法test()"+ ++k);
??if(k<2){
???throw new Exception();
??}
??
?}
}
?
這個類必須在連接點的包或者子包下面,
在SystemArchitecture里有定義
?@Pointcut("execution(* test.prefer.aspect.*.*(..))")
? public void businessService(){}
?
2)applicationContext.xml里配置 MyTestAspect
<bean id="test" class="test.prefer.aspect.MyTestAspect"/>
?
3)好了,看看效果吧
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.prefer.aspect.MyTestAspect;
public class example {
?
?public static void main(String args[]){
??
??ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
??MyTestAspect t =(MyTestAspect)ctx.getBean("test");
??try{
??t.test("");
??}catch(Exception e){
???System.out.println("main()中處理異常"+e);
??}
?}
}
輸出結果是:
環繞通知方法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............
這里是[ 目標 ]方法test()1
環繞通知方法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............
這里是[ 目標 ]方法test()
總結
以上是生活随笔為你收集整理的spring aop 环绕通知around和其他通知的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 06-Java 本地文件操作
- 下一篇: 介绍一款JavaScript播放器 -