我的Spring之旅——(三)AOP通知的几种类型

来源:互联网 发布:南昌市残疾淘宝培训 编辑:程序博客网 时间:2024/06/05 11:27

为了搞明白AOP通知的类型之间有什么区别,我也是走了一些小弯路,下面就把我遇见的坑坑洼洼扒拉出来凉一凉吧~

一、AOP的通知类型

1.前置通知(before advice):在连接点前面执行,对连接点不会造成影响(前置通知有异常的话,会对后续操作有影响)

2.正常返回通知(after returning advice):在连接点正确执行之后执行,如果连接点抛异常,则不执行

3.异常返回通知(after throw Advice):在连接点抛异常的时候执行

4.返回通知(after):无论连接点是正确执行还是抛异常,都会执行

5.环绕通知(around):在连接点前后执行(必须在环绕通知中决定是继续处理还是中断执行,使用PreceedingJoinPonit下的方法决定是继续还是中断

注:这里我不得不说一下了,上面第五条中红色标注的地方非常非常非常重要,菜鸟(哦不,可能笨鸟更适合我)就在这翻了一个很大的跟头大哭

二、两种实现方式

方法一:配置文件法

1.业务类

package lm.practice.services;/** * Created by Administrator on 2017/4/13. *//** * 业务实现类 */public class BankService {    /**     * 模拟银行转账系统     * @param form  转出者     * @param to  转入者     * @param count 金额     * @return     */    public boolean transfer(String form, String to, double count) {        if(count<100.0){            throw new IllegalArgumentException("最低转账金额不得少于100");        }        System.out.println(form+"向"+to+"中行账户转账"+count);        return false;    }}

2.切面类

package lm.practice.aop;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;/** * Created by Administrator on 2017/4/13. *//** * 切面类 */public class MyAdvices {    /**     * 前置通知     * @param joinPoint 连接点     */    public void before(JoinPoint joinPoint){        System.out.print("--------前置通知----------");    }    /**     * 正常返回通知     * @return     */    public boolean afterReturning(){        System.out.println("------正常返回通知--------");        return true;    }    /**     * 异常返回通知     * @return     */    public void afterThrow(){        System.out.print("-------异常返回通知-------");    }    /**     * 返回通知     * @return     */    public void after(){        System.out.println("----------返回通知--------");    }    /**     * 环绕通知     * @return     */    public boolean around(ProceedingJoinPoint joinPoint) throws Throwable {       System.out.println("--------环绕通知----------");       oinPoint.proceed();       return true;    }}

3.配置文件

<?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:aop="http://www.springframework.org/schema/aop"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">    <!--被代理对象-->    <bean id="bankService" class="lm.practice.services.BankService">    </bean>    <!--通知-->    <bean id="myAdvices" class="lm.practice.aop.MyAdvices"></bean>    <!--aop配置-->    <aop:config proxy-target-class="true">        <!--切面-->        <aop:aspect ref="myAdvices">            <!--切点-->            <aop:pointcut id="pointcut"  expression="execution(* lm.practice.services.*.*(..))"></aop:pointcut>            <!--连接通知方法与切点-->            <aop:before method="before" pointcut-ref="pointcut"></aop:before>            <aop:after-returning method="afterReturning" pointcut-ref="pointcut"></aop:after-returning>            <aop:after-throwing method="afterThrow" pointcut-ref="pointcut"></aop:after-throwing>            <aop:after method="after" pointcut-ref="pointcut"></aop:after>            <aop:around method="around" pointcut-ref="pointcut"></aop:around>        </aop:aspect>    </aop:config></beans>

4.测试类

package test;import lm.practice.services.BankService;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/** * Created by Administrator on 2017/4/13. */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "classpath:spring-aop-bank.xml")public class BankServiceTest {    @Autowired    private BankService bankService;    @Test    public void test(){       bankService.transfer("商行","中行",100.00);    }

4.运行结果


如果转账金额小于100的情况下,输出结果:


方法二、注解法

可以参照我之前写的博客自己试着进行


-------------------------------------------------------------------------以上是正确的代码---------------------------------------------------------

我现在就说一下我犯的一个错误:

package lm.practice.aop;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;/** * Created by Administrator on 2017/4/13. *//** * 切面类 */public class MyAdvices {    /**     * 前置通知     * @param joinPoint 连接点     */    public void before(JoinPoint joinPoint){        System.out.print("--------前置通知----------");    }    /**     * 正常返回通知     * @return     */    public boolean afterReturning(){        System.out.println("------正常返回通知--------");        return true;    }    /**     * 异常返回通知     * @return     */    public void afterThrow(){        System.out.print("-------异常返回通知-------");    }    /**     * 返回通知     * @return     */    public void after(){        System.out.println("----------返回通知--------");    }        /**     * 环绕通知     */    public void around(){        System.out.println("--------环绕通知----------");    }}

这是我犯错的时候的切面类的书写方法,报错信息如下:


org.springframework.aop.AopInvocationException: Null return value from advice does not match primitive return type for: public boolean lm.practice.services.BankService.transfer(java.lang.String,java.lang.String,double)

上面的就是控制台中那段很长的代码:通知的返回为空,与注入方法返回类型不匹配。

-------------------------------------------------------我的漫漫求解路----------------------------------------------------------

第一次尝试:首先我以为单纯的是返回类型的问题,就把切面类中的异常返回通知(afterReturning)返回值类型改成了boolen,结果不可行,依旧报错

第二次尝试:将不同通知类型分开写(没有完成,被导师否定,因为根源不在这)

第三次尝试:将配置文件的方式改成注解,还是不行

第四次尝试:导师捉急啊,直接一步一步引导我,说要抛开表面看实质,他是这样引导我的:首先问我每个通知类型的区别,然后问我around和after和before有什么区别,然后问我知道around有什么注意点吗,最后让我查一下,既然是around(环绕),那么怎么确定是不是会执行连接点呢?最后我查了一下,发现在使用around的时候必须要决定是继续执行还是中断执行,然后我这只笨鸟就在around中写了那么一段继续执行的代码,然后问题解决了

总结一下就是around必须要指定是继续执行还是中断执行(重要!重要!!重要!!!重要!!!!!)

到此我的spring学习就告一段落了,这里还有一个重要的知识点就是日志了,我这里用到的是log4j,具体的一些知识点,后续会分享出来~

呼呼~~下班啦再见

0 0
原创粉丝点击