spring aop 环绕通知 基于@aspectJ
2010-06-01 16:03
441 查看
前言:
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;
}
}
说明:
请注意切面实现了
二、在配置文件里配置这个切面
<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 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别:
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()
相关文章推荐
- springAOP基于xml的配置前后环绕通知
- 14Spring_AOP编程(AspectJ)_环绕通知
- 在idea创建spring项目,基于Aspectj的aop操作,执行前置和后置通知出现错误
- 基于@AspectJ配置Spring AOP(上)
- [Spring AOP] 基于AspectJ的@AfterReturning注释示例
- 9、SSM框架-Spring AOP之基于XML的声明式AspectJ(9)
- Spring学习-21:Spring的AOP:基于AspectJ的注解开发
- Spring Aop开发基于AspectJ注解方式的案例
- Spring基于annotation的AOP(AspectJ)
- 基于xml配置的spring aop 的实现日志 和为通知传递参数
- 框架 day37 Spring3,AOP,代理模式(动态/CGLIB/工厂bean),传统AOP,AspectJ框架(基于xml/注解),切入点表达式,jdbcTemplate
- 基于@AspectJ配置Spring AOP之一
- Spring AOP技术(基于AspectJ)的XML开发
- [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.
- 【Spring AOP】基于AspectJ的AOP基本使用
- 【spring】基于AspectJ的AOP
- 基于spring的前置后置及环绕通知
- Spring(十一)AspectJ框架开发AOP(基于xml)
- spring aop环绕通知
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我学spring3