spring aop aspect相关顺序及相关通知使用

一、好言

有时候,上天没有给你要的,不是因为你不配,而是因为你指的更好的。


二、背景

最近看看《spring揭秘》这本书,也顺带看看源码,第一遍希望能熟悉基本的用法和理解一些简单的源码。


三、内容

3.1、aspect顺序

对于多个Advice 来说,如果它们引用的Pointcut定义恰好匹配同一个Jointpoint的时候,在这同一个Jointpoint 的时候,在这同一个Jointpoint上,这些Advice改按照什么顺序执行了?对于这个问题,我们从两个角度来看

当这些Advice都声明在同一个Aspect内的时候,如果匹配同一个Jointpoint的多个Advice都声明在同一个Aspect定义中,那么这些Advice的执行顺序,由他们在Aspect中的声明顺序决定。最先声明的Advice拥有最高的优先级。对于Before Advice来说,拥有最高优先级的最先运行;而对于AfterReturningAdvice,拥有最高优先级的则最后运行。

eg:

/**
 * @Title: MultiAdvicesAspect
 * @Package org.mouse.spring.aspect
 * @Description: 测试所有的切面advice
 * @author Mahone Wu
 * @date 2017/12/12 15:42
 * @version V1.0
 */
@Component
@Aspect
public class MultiAdvicesAspect {

    @Pointcut("execution(boolean *.execute(String,..))")
    public void taskExecution(){}

    @Before("taskExecution()")
    public void beforeOne(){
        System.out.println("before one");
    }

    @Before("taskExecution()")
    public void beforeTwo(){
        System.out.println("before two");
    }

    @AfterReturning("taskExecution()")
    public void afterReturningOne(){
        System.out.println("after returing one");
    }

    @AfterReturning("taskExecution()")
    public void afterReturningTwo()
    {
        System.out.println("after returing two");
    }
}

方法:

/**
 * @Title: MultiAdvicesAspect
 * @Package org.mouse.spring.aspect
 * @Description: 实现类
 * @author Mahone Wu
 * @date 2017/12/12 15:50
 * @version V1.0
 */
@Service
public class AdviceImpl {

    public boolean execute(String name,String msg){
        System.out.println(msg +","+name);
        return Boolean.TRUE;
    }
}

配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
             http://www.springframework.org/schema/aop
             http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="org.mouse.spring.aspect"></context:component-scan>
    <!-- 自动为切面方法中匹配的方法所在的类生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试类

/**
 * @Title: MultiAdvicesAspect
 * @Package org.mouse.spring.aspect
 * @Description: test
 * @author Mahone Wu
 * @date 2017/12/12 15:42
 * @version V1.0
 */
public class TestMain {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/aspect/aspect.xml");
        AdviceImpl adviceImpl = (AdviceImpl) ctx.getBean("adviceImpl");
        adviceImpl.execute("mahone", "hello");
    }

}

打印结果


图片.png

3.2、各种切面

先看看一个异常:

前置通知:方法名称execute,传入参数:2
Exception in thread "main" org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public boolean org.mouse.spring.aspect.AdviceImpl.execute(java.lang.String,java.lang.String)
    at org.springframework.aop.framework.CglibAopProxy.processReturnType(CglibAopProxy.java:361)
    at org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:84)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:657)
    at org.mouse.spring.aspect.AdviceImpl$$EnhancerBySpringCGLIB$$eaf4c242.execute(<generated>)
    at org.mouse.spring.aspect.TestMain.main(TestMain.java:19)
hello,Mahone
环绕通知:方法:execute,返回结果:true
后置通知:方法名称:execute,after method
返回通知:方法名称:execute,返回结果:null

对于上面的异常,是由于配置的环绕通知没加返回值得缘故,如下代码

@Around(value = "taskExecution()")
    public void aroundException(ProceedingJoinPoint pjp){
        String methodName = pjp.getSignature().getName();
        Object result = null;
        try {
            result = pjp.proceed();
            System.out.println("环绕通知:方法:"+methodName+",返回结果:"+result);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

将void改为Object设置成有返回值方法即可。
下面我们看看各种切面,代码如下

/**
 * @Title: MultiAdvicesAspect
 * @Package org.mouse.spring.aspect
 * @Description: 测试所有的切面advice
 * @author Mahone Wu
 * @date 2017/12/12 16:20
 * @version V1.0
 */
@Component
@Aspect
public class MultiAdvicesAllAspect {

    @Pointcut("execution(boolean *.execute(String,..))")
    public void taskExecution(){}

    /**
     * 前置通知
     */
    @Before("taskExecution()")
    public void before(JoinPoint jp){
        String methodName = jp.getSignature().getName();
        Object[] args = jp.getArgs();
        System.out.println("前置通知:方法名称"+methodName+",传入参数:"+args.length);
    }


    /**
     * 环绕通知
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around(value = "taskExecution()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        String methodName = pjp.getSignature().getName();
        Object result = null;
        try {
             result = pjp.proceed();
            System.out.println("环绕通知:方法:"+methodName+",返回结果:"+result);
        } catch (Throwable throwable) {//如果配置了异常通知,则这里需要抛出异常信息
            throw throwable;
        }
        return result;
    }

    /**
     * 后置通知
     * @param jp
     */
    @After("taskExecution()")
    public void after(JoinPoint jp){
        String methodName = jp.getSignature().getName();
        System.out.println("后置通知:方法名称:"+methodName+",after method");
    }

    /**
     * 返回通知
     * @param jp
     * @param result
     */
    @AfterReturning(value = "taskExecution()",returning = "result")
    public void afterReturning(JoinPoint jp,Object result){
        String methodName = jp.getSignature().getName();
        System.out.println("返回通知:方法名称:"+methodName+",返回结果:"+result);
    }

    /**
     * 异常通知
     * @param jp
     * @param ex
     */
    @AfterThrowing(value = "taskExecution()",throwing = "ex")
    public void afterThrowing(JoinPoint jp,Exception ex){
        String methodName = jp.getSignature().getName();
        System.out.println("异常通知,方法名:"+methodName+"发生的异常ex="+ex);
    }

![图片.png](http://upload-images.jianshu.io/upload_images/1456372-5a49833ae630f17a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


这里给出了相关代码,说明两点
(1)、后置通知在返回通知前执行
我按照理解之前觉得返回通知在后置通知之前的,但是实际测试后发现,后置通知在返回通知前执行。

(2)、对于异常通知
如果再环绕通知的时候捕获到异常而没有抛出的话,那么异常通知将没有作用,所以如果配置了异常通知,在环绕通知中捕获的异常需要继续抛出。

给出实现类新增的方法:

/**
 * @Title: MultiAdvicesAspect
 * @Package org.mouse.spring.aspect
 * @Description: 实现类
 * @author Mahone Wu
 * @date 2017/12/12 15:50
 * @version V1.0
 */
@Service
public class AdviceImpl {

    public boolean execute(String name,String msg){
        System.out.println(msg +","+name);
        return Boolean.TRUE;
    }


    public boolean execute(String name,int a){
        int b = 1 / a;
        System.out.println("name="+name);
        return Boolean.TRUE;
    }

    public boolean execute(int a){
        int b = 1 / a;
        return Boolean.TRUE;
    }
}

dsa

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342