springaop环绕通知around和其他通知的区别
前⾔:
的环绕通知和前置通知,后置通知有着很⼤的区别,主要有两个重要的区别:
1)⽬标⽅法的调⽤由环绕通知决定,即你可以决定是否调⽤⽬标⽅法,⽽前置和后置通知是不能决定的,他们只是在⽅法的调⽤前后执⾏通知⽽已,即⽬标⽅法肯定是要执⾏的。
2)环绕通知可以控制返回对象,即你可以返回⼀个与⽬标对象完全不同的返回值,虽然这很危险,但是你却可以办到。⽽后置⽅法是⽆法办到的,因为他是在⽬标⽅法返回值后调⽤
这⾥是经过我⾃⼰测试的过的例⼦,使⽤⾯向切⾯来处理⼀些问公共的问题,⽐如,权限管理,事务的委托
下⾯的例⼦就是使⽤环绕通知,当程序发⽣异常时,重复提交请求,重复的次数是可以设定的
当我们开发企业级应⽤时,通常会想要从⼏个切⾯来引⽤模块化的应⽤和特定操作的集合,下⾯是⼀个典型的通⽤切⾯,看起来可能像下⾯这样(这也是Spring⽂档⾥的)
package test.prefer.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
spring framework和spring的关系public class SystemArchitecture {
/**
* A join point is in the web layer if the method is defined
* in a type in someapp.web package or any sub-package
* under that.
*/
@Pointcut("someapp.web..*)")
public void inWebLayer() {}
/
**
* A join point is in the service layer if the method is defined
* in a type in someapp.service package or any sub-package
* under that.
*/
@Pointcut("someapp.service..*)")
public void inServiceLayer(){}
/**
* A join point is in the data access layer if the method is defined
* in a type in someapp.dao package or any sub-package
* under that.
*/
@Pointcut("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 someapp.abc.service def.service) then
* the pointcut expression "execution(* 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(* someapp.dao.*.*(..))")
public void dataAccessOperation(){}
}
⼀、定义⾃⼰的⼀个切⾯
/*
*⽂件名:ConcurrentOperationExecutor.
*描述:<;描述>
*修改⼈:Administrator
*/
package test.prefer.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import Ordered;
/**
* @author
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(){
der;
}
public void setOrder(int 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)l⾥配置 MyTestAspect
<bean id="test" class="test.prefer.aspect.MyTestAspect"/>
3)好了,看看效果吧
package test;
import t.ApplicationContext;
import t.support.ClassPathXmlApplicationContext;
public class example {
public static void main(String args[]){
ApplicationContext ctx = new ClassPathXmlApplicationContext("l"); MyTestAspect t =(Bean("test");
try{
}catch(Exception e){
System.out.println("main()中处理异常"+e);
}
}
}
输出结果是:
环绕通知⽅法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............
这⾥是[⽬标]⽅法test()1
环绕通知⽅法[ doConcurrentOperation(ProceedingJoinPoint pjp) ].............
这⾥是[⽬标]⽅法test()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论