spring aop 环绕通知around和其他通知的区别
前言:
?????spring?的環(huán)繞通知和前置通知,后置通知有著很大的區(qū)別,主要有兩個(gè)重要的區(qū)別:
1)?目標(biāo)方法的調(diào)用由環(huán)繞通知決定,即你可以決定是否調(diào)用目標(biāo)方法,而前置和后置通知???是不能決定的,他們只是在方法的調(diào)用前后執(zhí)行通知而已,即目標(biāo)方法肯定是要執(zhí)行的。
2)??環(huán)繞通知可以控制返回對(duì)象,即你可以返回一個(gè)與目標(biāo)對(duì)象完全不同的返回值,雖然這很危險(xiǎn),但是你卻可以辦到。而后置方法是無(wú)法辦到的,因?yàn)樗窃谀繕?biāo)方法返回值后調(diào)用
?? 這里是經(jīng)過(guò)我自己測(cè)試的過(guò)的例子,使用面向切面來(lái)處理一些問(wèn)公共的問(wèn)題,比如,權(quán)限管理,事務(wù)的委托
下面的例子就是使用環(huán)繞通知,當(dāng)程序發(fā)生異常時(shí),重復(fù)提交請(qǐng)求,重復(fù)的次數(shù)是可以設(shè)定的
??? 當(dāng)我們開(kāi)發(fā)企業(yè)級(jí)應(yīng)用時(shí),通常會(huì)想要從幾個(gè)切面來(lái)引用模塊化的應(yīng)用和特定操作的集合,下面是一個(gè)典型的通用切面,看起來(lái)可能像下面這樣(這也是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(){}
}
?
?一、定義自己的一個(gè)切面
/*
*文件名: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 {?
??? //環(huán)繞通知處理方法
????? int numAttempts = 0;
????? Exception lockFailureException;
????? do {
???????? numAttempts++;
???????? try {?
??????? ? System.out.println("環(huán)繞通知方法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............");
??????????? return pjp.proceed();
???????? }
???????? catch(Exception ex) {
??????????? lockFailureException = ex;
???????? }
????? }
????? while(numAttempts <= this.maxRetries);
????? throw lockFailureException;
?? }
}
?
說(shuō)明:
??? 請(qǐng)注意切面實(shí)現(xiàn)了?Ordered?接口,這樣我們就可以把切面的優(yōu)先級(jí)設(shè)定為高于事務(wù)通知 (我們每次重試的時(shí)候都想要在一個(gè)全新的事務(wù)中進(jìn)行)。maxRetries和order?屬性都可以在Spring中配置。主要的動(dòng)作在doConcurrentOperation這個(gè)環(huán)繞通知方法中發(fā)生。 請(qǐng)注意這個(gè)時(shí)候我們所有的businessService()方法都會(huì)使用這個(gè)重試策略。 我們首先會(huì)嘗試處理,如果得到一個(gè)Exception異常, 我們僅僅重試直到耗盡所有預(yù)設(shè)的重試次數(shù)(spring開(kāi)發(fā)文檔)
?
二、在配置文件里配置這個(gè)切面
<aop:aspectj-autoproxy/>
<bean id="concurrentOperationExecutor"
? class="test.prefer.aspect.ConcurrentOperationExecutor">
???? <property name="maxRetries" value="3"/>
???? <property name="order" value="100"/>??
</bean>
?
好了,下面我們就試一下效果吧
?
三、測(cè)試效果
??? 1)新建一個(gè)測(cè)試的bean: MyTestAspect,代碼如下:
package test.prefer.aspect;
/**
?* 這是一個(gè)切面類
?*/
import org.aspectj.lang.annotation.Aspect;
public class MyTestAspect {
?int k=0;
?public void test(String args) throws Exception{
??System.out.println("這里是[ 目標(biāo) ]方法test()"+ ++k);
??if(k<2){
???throw new Exception();
??}
??
?}
}
?
這個(gè)類必須在連接點(diǎn)的包或者子包下面,
在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);
??}
?}
}
輸出結(jié)果是:
環(huán)繞通知方法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............
這里是[ 目標(biāo) ]方法test()1
環(huán)繞通知方法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............
這里是[ 目標(biāo) ]方法test()
總結(jié)
以上是生活随笔為你收集整理的spring aop 环绕通知around和其他通知的区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 06-Java 本地文件操作
- 下一篇: 修改hosts立刻生效不必重启