前言:

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/>

<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和其他通知的区别的更多相关文章

  1. spring aop环绕通知

    [Spring实战]—— 9 AOP环绕通知   假如有这么一个场景,需要统计某个方法执行的时间,如何做呢? 典型的会想到在方法执行前记录时间,方法执行后再次记录,得出运行的时间. 如果采用Sprin ...

  2. [转载] spring aop 环绕通知around和其他通知的区别

    前言: spring 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别: 1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知   是不能决定的,他们只 ...

  3. Spring AOP环绕异常影响的报错

    最近遇到一个问题,异常是: java.lang.ClassCastException: org.springframework.http.ResponseEntity cannot be cast t ...

  4. Spring AOP JDK动态代理与CGLib动态代理区别

    静态代理与动态代理 静态代理 代理模式 (1)代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理. (2)静态代理由 业务实现类.业务代理类 两部分 ...

  5. Spring 通过XML配置文件以及通过注解形式来AOP 来实现前置,环绕,异常通知,返回后通知,后通知

    本节主要内容: 一.Spring 通过XML配置文件形式来AOP 来实现前置,环绕,异常通知     1. Spring AOP  前置通知 XML配置使用案例     2. Spring AOP   ...

  6. Spring技术内幕:Spring AOP的实现原理(一)

    一.SpringAOP的概述 1.AOP概念 AOP是Aspect-Oriented Programming(面向切面编程)的简称.维基百科的解释例如以下: Aspect是一种新的模块化机制,用来描写 ...

  7. Spring AOP概念及作用

    一:SpringAOP概念 面向切面编程(Aspect Oriented Programming)提高了另一种角度来思考程序的结构,通过预编译方式和运行期间的动态代理实现程序功能的统一维护的一种技术. ...

  8. 5.3 Spring5源码--Spring AOP使用接口方式实现

    Spring 提供了很多的实现AOP的方式:Spring 接口方式,schema配置方式和注解. 本文重点介绍Spring使用接口方式实现AOP. 使用接口方式实现AOP以了解为目的. 更好地理解动态 ...

  9. Spring AOP实现方式一【附源码】

    基本代理模式  纯POJO切面 源码结构: 1.首先我们新建一个接口,love 谈恋爱接口. package com.spring.aop; /** * 谈恋爱接口 * * @author Admin ...

随机推荐

  1. JS组件系列——Bootstrap寒冬暖身篇:弹出框和提示框效果以及代码展示

    前言:对于Web开发人员,弹出框和提示框的使用肯定不会陌生,比如常见的表格新增和编辑功能,一般常见的主要有两种处理方式:行内编辑和弹出框编辑.在增加用户体验方面,弹出框和提示框起着重要的作用,如果你的 ...

  2. 初次尝试用Kotlin实现Android项目

    Kotlin: The Swift of Android 起这个文内标题的原因很简单,就是对Kotlin抱有希望--能使Android的开发更简洁.高效及安全.知道Kotlin是从简书的一篇短文,越来 ...

  3. 备忘:spring jdbc事务代码 mybatis, nhibernate

    http://files.cnblogs.com/files/mikelij/mymavenMar1.rar

  4. VMware网络设置详解

    标签: 网络vmware虚拟机web服务network 2009-05-19 22:23 27537人阅读 评论(7) 收藏 举报 分类: 基于类linux的开发(171) 我们知道,VMwareWo ...

  5. 【IIS】iis6.1下添加两个ftp站点,

    1,添加本地账户或密码||组  :[控制面板-->管理工具-->计算机管理器-->系统工具-->本地用户和组] 2,IIS站点目录先(添加FTP站点)[注意:多个站点多个端口] ...

  6. jQuery 选择同时包含两个class的元素的实现方法

    Jquery选择器 多个 class属性参照以下案例 <element class="a b good list card"> 1. 交集选择: $(".a. ...

  7. WCF错误:由于目标计算机积极拒绝,无法连接

    今天学习WCF时用C#重写测试例子时,发生错误:由于目标计算机积极拒绝,无法连接.找了N久,网上也没有找到实际的解决方法.查看netstat -an发现当自承载宿主运行时,没有侦听配置的端口.开始总以 ...

  8. BZOJ 1432: [ZJOI2009]Function

    1432: [ZJOI2009]Function Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1046  Solved: 765[Submit][Sta ...

  9. mac 常用地址

    1.hosts   配置文件地址 /private/etc/hosts 2.apache 配置文件地址 /etc/apache2/httpd.conf 3.Xcode 插件地址 ~/Library/A ...

  10. Typescript Mixins(混合)

    除了惯例的面对对象的思想,另一种较流行的通过可复用组件创建类的方法是将简单的类混合到一起.你可能对这种混合的方式比较熟悉或对Scala语言的特性有理解,这种模式在JavaScript社区也有一定的人气 ...