美文网首页我爱编程
spring详解(九)「AOP」

spring详解(九)「AOP」

作者: FTOLsXD | 来源:发表于2017-02-22 11:20 被阅读330次

    定义AfterReturning增强处理

    AfterReturning增强处理在目标方法正常完成之后织入。

    类似于使用@Before Annotation可标注Before增强处理,使用@AfterReturning Annation来标注@AfterRetuning增强处理。
    使用@AfterReturning Annotation可以指定如下属性:
    <li>pointcut/value:这两个属性的作用是一样的,他们都是指定该切入点对应的切入表达式,当指定pointcut属性,value属性值将会被覆盖。
    <li>returning:指定一个返回值形参,增强处理的方法可以通过该形参名来访问目标方法的返回值。

    @Aspect
    publicclass AfterReturningAdviceTest {
    @AfterReturning(pointcut="execution(* cn.hb.spring..(..))",returning="obj")
    publicvoid log(Object obj){
    System.out.println("获取目标方法返回值"+obj);
    System.out.println("模拟日志记录功能....");
    }
    }

    如果log有参数,returning属性一定要配置。`如果参数不止一个,那么目标方法将不会执行必须要配置`args表达式`。`
    **注意**:`使用returning属性还有另一个额外的作用:它可以限定切入点只匹配具有对应返回类型的方法。加入上面的log的参数是String类型,`则该切入点只匹配cn.hb.spring包下的返回值类型为String的所有方法。虽然AfterReturning增强处理可以访问到目标方法的返回值,但不可以改变目标方法返回值`。`
    
    ---
    **定义AfterThrowing增强处理**:
    
    >AfterThrowing增强处理主要用于程序中未处理的异常。
    
    >使用@AfterThrowing Annotation时可以指定如下两个属性:
    <li>**pointcut/value**:这两个属性的作用是一样的,他们都是指定该切入点对应的切入表达式,当指定pointcut属性,value属性值将会被覆盖。
    <li>**throwing**:指定一个返回值形参名,增强处理定义的方法可以通过该形参名来访问目标方法中所抛出的异常对象。
    
    >```
    @Aspect
    public class AfterThrowingAdviceTest {
        @AfterThrowing(pointcut ="execution(* cn.hb.spring.*.*(..))", throwing ="th")
        public void doRecoveryActions(Throwable th) {
            System.out.println("目标方法中抛出的异常" + th);
            System.out.println("模拟抛出异常的增强处理/.....");
        }
    }
    
    @Component
    publicclass Chineseimplements Person {
    @Override
    publicString sayHello(String word) {
        try {
            System.out.println("sayHello方法开始执行...");
            new FileInputStream("a.txt");
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        }
            return word;
    }
        publicvoid eat(String food) {
            System.out.println("我正在吃" + food);
        }
        publicvoid divide(){
            int a = 5/0;
            System.out.println("divide执行完毕/"+a);
        }
    }
    

    //Chinese c = (Chinese)ac.getBean("chinese");//会出错,不能转换为Chinese
    Person c = (Person)ac.getBean("chinese");
    System.out.println(c.sayHello("你好--Before"));
    c.eat("西瓜");
    c.divide();

    >**上面的程序的sayHello和divided两个方法都会抛出异常,但是sayHello方法中的异常将由该方法显示捕捉,所以Spring AOP不会处理该异常。**
    
    >**而divide方法将抛出算术异常,且该异常没有被任何程序所处理,故Spring AOP会对该异常进行处理。**
    
    >**使用throwing属性还有另一个作用:它可以用于限定切入点只匹配指定类型的异常。类似AfterRetuning的returning 属性。**
    
    >Spring AOP的AfterThrowing处理虽然可以对目标方法的异常进行处理,但是这种处理与直接使用catch捕捉是不同的:
    `catch意味完全处理该异常,如果catch没有重新抛出一次异常,则方法可以正常结束,而AfterThrowing处理虽然处理了异常,但它不能完全处理异常,该异常依然会传播到上一级调用者。`
    
    ---
    **定义After增强处理**:
    After增强处理与AfterReturning增强处理有点相似,但是也有不同:
    <li>AfterRetuning只在目标方法成功完成后才被织入。
    <li>After增强处理不管目标方法如何结束,都会被织入。
    
    >因为一个方法不管是如何结束,After增强处理它都会被织入,因此After增强处理必须处理正常返回和异常返回两种情况,这种增强处理通常用于资源释放。
    使用@After Annotation标注一个方法,即可将该方法转成After增强处理,使用@After Annotation增强处理需要指定一个value属性,该属性值用于指定该增强处理被织入的切入点,既可以是一个已有的切入点也可以直接指定切入点表达式。
    

    @Aspect
    publicclass AfterAdviceTest {
    @After("execution(* cn.huaxia.spring..(..))")
    publicvoid release(){
    System.out.println("模拟方法结束后资源释放....");
    }
    }

    **After增强处理非常类似于异常处理中的finally块的作用-----无论结果如何,它总在方法执行结束之后被织入,因此特别适合进行资源回收。**
    
    ---
    
    ** Around增强处理**:
    
    @Around Annotation用于标注Around的增强处理,Around的增强处理是比较强的增强处理,它近似等于Before和AfterRetuning增强处理的总和,Around增强处理既可以在目标方法之前执行,也可以在执行目标方法之后织入增强动作。
    
    与Before增强处理和AfterReturning增强处理不同的是Around增强处理可以决定目标方法执行在什么时候执行,如何执行,甚至可以阻止目标方法执行。Around增强处理可以改变执行目标方法的参数值,还可以改变执行目标方法之后的返回值。
    
    >使用@Around Annotation时需要指定value属性,该属性用来指定该增强处理被织入的切入点。
    当定义一个Around增强处理方法时,该方法的第一个形参必须是ProceedingJoinPoint类型(至少包含一个形参)。
    在增强处理方法体内,调用ProceedingJoinPoint的process方法时,还可以传入一个Object[]对象,该数组中的值将被传入目标方法作为执行方法的的实参。-------这就是Around增强处理可以完全控制目标方法执行时机、如何执行的关键。`如果程序没有调用ProceedingJoinPoint的proceed方法则目标方法不会执行。`
    

    @Aspect
    publicclass AroundAdviceTest {
    @Around("execution(* cn.huaxia.spring..(..))")
    public Object proceedTX(ProceedingJoinPoint pre)throws Throwable {
    System.out.println("开始事务.....");
    Object obj = pre.proceed(new String[] {"被修改的参数" });
    System.out.println("结束事务.....");
    return obj +",新增的内容";
    }
    }

    **当调用ProceedingJoinPonint的proceed方法时,传入的Object[]参数值将作为目标方法的参数,如果传入的Object[]参数的长度和目标方法参数个数不匹配,或者Object[]数组元素与目标方法所需的参数不匹配,程序就会抛出异常。
    为了能获取目标方法参数的个数和类型,这就需要增强处理方法能够访问执行目标方法的参数了。**
    
    访问目标方法的参数:
    
    >访问目标方法最简单的的做法是定义增强处理方法时将第一个参数定义为**JoinPoint类型**,当增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点,JoinPoint包含如下几个常用的方法:
        <li>Object[] getArgs():返回执行目标方法的参数;
        <li>Signature getSignature():返回被增强的方法的相关信息;
        <li>Object getTarget():返回被织入增强处理的目标方法;
        <li>Object getThis():返回AOP框架为目标对象生成的代理对象。
    `如:`
    

    @Aspect
    public class FourAdviceTest {
    @Around("execution(* cn.hb.spring.service..(..))")
    public Object proceedTX(ProceedingJoinPoint pre) throws Throwable {
    System.out.println("Around增强处理:执行目标方法前,执行模拟开启事务.......");
    Object[] objs = pre.getArgs();
    if (objs != null && objs.length > 0
    && objs[0].getClass() == String.class) {
    objs[0] = "被修改的参数";
    }
    Object obj = pre.proceed(objs);
    System.out.println("Around增强处理:执行目标方法之后,模拟结束事务.....");
    return obj + ",新增加的内容";
    }
    @Before("execution(* cn.hb.spring.service..(..))")
    public void authority(JoinPoint jp) {
    System.out.println("Before增强:模拟权限检查");
    System.out.println("Before增强:被织入增强处理的目标方法:"
    + jp.getSignature().getName());
    System.out
    .println("Before增强:目标方法的参数为:" + Arrays.toString(jp.getArgs()));
    System.out.println("Before增强:被注入增强的处理 的目标对象:" + jp.getTarget());
    }
    @AfterReturning(pointcut="execution(* cn.hb.spring.service..(..))",returning="obj")
    public void log(JoinPoint jp, Object obj) {
    System.out.println("AfterReturning增强:获取目标方法的返回值:" + obj);
    System.out.println("AfterReturning增强:模拟日志记录功能.....");
    System.out.println("AfterReturning增强:被织入增强处理的目标方法:"
    + jp.getSignature().getName());
    System.out.println("AfterReturning增强:目标方法的参数为:"
    + Arrays.toString(jp.getArgs()));
    System.out.println("AfterReturning增强:被注入增强的处理 的目标对象:" + jp.getTarget());
    }
    @After("execution(* cn.huaxia.spring.service..(..))")
    public void release(JoinPoint jp) {
    System.out.println("After增强:模拟方法结束后,资源释放.....");
    System.out.println("After增强:被织入增强处理的目标方法:"
    + jp.getSignature().getName());
    System.out.println("After增强:目标方法的参数为:" + Arrays.toString(jp.getArgs()));
    System.out.println("After增强:被注入增强的处理 的目标对象:" + jp.getTarget());
    }
    }

    `输出结果:`
    

    Around增强处理:执行目标方法之后,模拟结束事务.....
    AfterReturning增强:获取目标方法的返回值:被修改的参数,新增加的内容
    AfterReturning增强:模拟日志记录功能.....
    AfterReturning增强:被织入增强处理的目标方法:sayHello
    AfterReturning增强:目标方法的参数为:[被修改的参数]
    AfterReturning增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
    After增强:模拟方法结束后,资源释放.....
    After增强:被织入增强处理的目标方法:sayHello
    After增强:目标方法的参数为:[被修改的参数]
    After增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
    被修改的参数,新增加的内容
    Around增强处理:执行目标方法前,执行模拟开启事务.......
    Before增强:模拟权限检查
    Before增强:被织入增强处理的目标方法:eat
    Before增强:目标方法的参数为:[被修改的参数]
    Before增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
    我正在吃:被修改的参数
    Around增强处理:执行目标方法之后,模拟结束事务.....
    AfterReturning增强:获取目标方法的返回值:null,新增加的内容
    AfterReturning增强:模拟日志记录功能.....
    AfterReturning增强:被织入增强处理的目标方法:eat
    AfterReturning增强:目标方法的参数为:[被修改的参数]
    AfterReturning增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
    After增强:模拟方法结束后,资源释放.....
    After增强:被织入增强处理的目标方法:eat
    After增强:目标方法的参数为:[被修改的参数]
    After增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
    Around增强处理:执行目标方法前,执行模拟开启事务.......
    Before增强:模拟权限检查
    Before增强:被织入增强处理的目标方法:divide
    Before增强:目标方法的参数为:[]
    Before增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
    After增强:模拟方法结束后,资源释放.....
    After增强:被织入增强处理的目标方法:divide
    After增强:目标方法的参数为:[]
    After增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6

     Spring AOP采用和AsoectJ一样的优先顺序来织入增强:**在"进入"连接点时**,最高等级的增强处理将先织入(所以给定两个Before增强处理中,优先级高的那个会执行),**在"退出"连接点时**,最高优先等级的增强处理将会最后织入。
    
    >4个增强处理的优先等级如下(从低到高):
    `Before增强处理--->Around增强处理--->AfterReturning增强处理--->After增强处理`
    
    >当两个不同的两个增强处理需要在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这两个增强处理,如果应用需要指定不同切面里增强处理的优先级,Spring提供了两个解决方案:
    <li>`让切面类实现org.springframework.core.Ordered接口,实现该接口提供的 int getOrder()方法,方法返回值越小,则优先级越高。`
    
    ><li>`直接使用@Order Annotation 来标注一个切面类,使用@Order Annotation时可以指定一个int 型的value属性,该属性值越小,优先等级越高。`
    
    
    
    

    相关文章

      网友评论

        本文标题:spring详解(九)「AOP」

        本文链接:https://www.haomeiwen.com/subject/ptgpwttx.html