spring aop 环绕通知around和其他通知的区别

本文内容纲要: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 接口,这样我们就可以把切面的优先级设定为高于事务通知 (我们每次重试的时候都想要在一个全新的事务中进行)。maxRetriesorder 属性都可以在Spring中配置。主要的动作在doConcurrentOperation这个环绕通知方法中发生。 请注意这个时候我们所有的businessService()方法都会使用这个重试策略。 我们首先会尝试处理,如果得到一个Exception异常, 我们仅仅重试直到耗尽所有预设的重试次数(spring开发文档)

二、在配置文件里配置这个切面

aop:aspectj-autoproxy/




好了,下面我们就试一下效果吧

三、测试效果

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

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和其他通知的区别

原文链接:https://www.cnblogs.com/gmq-sh/p/6018587.html

以上是 spring aop 环绕通知around和其他通知的区别 的全部内容, 来源链接: utcz.com/z/362834.html

回到顶部