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

为了搞明白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,具体的一些知识点,后续会分享出来~

呼呼~~下班啦再见

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值