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

    xiaoxiao2021-04-14  53

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

    呼呼~~下班啦

    转载请注明原文地址: https://ju.6miu.com/read-670256.html

    最新回复(0)