18-spring学习-AOP深入操作
Posted 美好的明天
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18-spring学习-AOP深入操作相关的知识,希望对你有一定的参考价值。
范例:定义一个参数拦截
package com.Spring.aop; import org.springframework.stereotype.Component; @Component public class ServiceAspect { public void serviceBefore() { System.out.println("AOP切面执行日志记录操作"); } public void serviceBefore2(Object arg) { System.out.println("AOP切面执行增加前操作,参数="+arg); } public void serviceAfter() { System.out.println("AOP切面执行事务处理操作"); } }
配置也修改:
<aop:config> <!-- 定义程序的切入点 --> <aop:pointcut expression="execution(* com.Spring..*.*(..)))" id="pointcut"/> <!-- 这里ref的对象是通过annotation配置@Component出来的, --> <!-- 定义面向方面的处理类 --> <aop:aspect ref="serviceAspect"> <aop:before method="serviceBefore2" pointcut-ref="pointcut"/> <aop:after method="serviceAfter" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy proxy-target-class="true"/>
此时运行报错。
此时serviceBefore2方法有参数了,就需要修改了。
范例:定义切入点表达式
这里通过 and args() 和arg-names来指定要传入操作前方法的参数。
<aop:config> <!-- 定义程序的切入点 --> <aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/> <!-- 这里ref的对象是通过annotation配置@Component出来的, --> <!-- 定义面向方面的处理类 --> <aop:aspect ref="serviceAspect"> <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/> <aop:after method="serviceAfter" pointcut="execution(* com.Spring..*.*(..)))"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy proxy-target-class="true"/>
运行结果:
因为after方法没有参数,不能直接使用第一个定义的切入点,所以这里after方法重新指定一个切入点,
而before是有参数的,直接使用第一个定义的切入点就行了。
除了操作之前拦截,也可以针对返回的结果进行拦截。
范例:针对返回结果拦截
package com.Spring.aop; import org.springframework.stereotype.Component; @Component public class ServiceAspect { public void serviceBefore() { System.out.println("AOP切面执行日志记录操作"); } public void serviceBefore2(Object arg) { System.out.println("AOP切面执行增加前操作,参数=" +arg); } public void serviceAfter() { System.out.println("AOP切面执行事务处理操作"); } public void serviceAfterReturn(Object val) //表示操作结果 { System.out.println("AOP切面操作完成,返回结果:"+val); } }
配置里面修改:
<aop:config>
<!-- 定义程序的切入点 -->
<aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/>
<!-- 这里ref的对象是通过annotation配置@Component出来的, -->
<!-- 定义面向方面的处理类 -->
<aop:aspect ref="serviceAspect">
<aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/>
<aop:after method="serviceAfter" pointcut="execution(* com.Spring..*.*(..)))"/>
<aop:after-returning method="serviceAfterReturn" pointcut="execution(* com.Spring..*.*(..)))" returning="haha" arg-names="haha"/>
</aop:aspect>
</aop:config>
这里通过returning和arg-names来传递返回结果给操作完成后返回方法:serviceAfterReturn,做完这个方法的参数。
执行结果:
除了返回结果的拦截之外,还能进行异常处理的拦截操作。
范例:修改MemberServiceImpl
package com.Spring.Test; import org.apache.commons.lang.NullArgumentException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.Spring.Service.IMemberService; import com.Spring.Service.Impl.MemberServiceImpl; import com.Spring.Vo.Member; public class TestMemberService { public static void main(String args[]) { throw new NullArgumentException("我来抛出一个异常"); /* ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); IMemberService ser=ctx.getBean("memberServiceImpl",MemberServiceImpl.class); Member vo=new Member(); vo.setMid("hello"); vo.setName("你好"); System.out.println(ser.insert(vo)); */ } }
增加拦截处理操作
package com.Spring.aop; import org.springframework.stereotype.Component; @Component public class ServiceAspect { public void serviceBefore() { System.out.println("AOP切面执行日志记录操作"); } public void serviceBefore2(Object arg) { System.out.println("AOP切面执行增加前操作,参数=" +arg); } public void serviceAfter() { System.out.println("AOP切面执行事务处理操作"); } public void serviceAfterReturn(Object val) //表示操作结果 { System.out.println("AOP切面操作完成,返回结果:"+val); } public void serviceAfterThrow(Exception e) //表示操作结果 { System.out.println("AOP切面操作出现异常:"+e); } }
配置:
<aop:config> <!-- 定义程序的切入点 --> <aop:pointcut expression="execution(* com.Spring..*.*(..)) and args(vo))" id="pointcut"/> <!-- 这里ref的对象是通过annotation配置@Component出来的, --> <!-- 定义面向方面的处理类 --> <aop:aspect ref="serviceAspect"> <aop:before method="serviceBefore2" pointcut-ref="pointcut" arg-names="vo"/> <aop:after method="serviceAfter" pointcut="execution(* com.Spring..*.*(..)))"/> <aop:after-returning method="serviceAfterReturn" pointcut="execution(* com.Spring..*.*(..)))" returning="haha" arg-names="haha"/> <aop:after-throwing method="serviceAfterThrow" pointcut="execution(* com.Spring..*.*(..)))" arg-names="e" throwing="abc"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy proxy-target-class="true"/>
这里因为需要传递异常参数,所以需要arg-names和throwing,但是这两个的值随便写就像了,不用想对应起来。
运行结果:
以上几个拦截器已经可以处理AOP可以处理的范畴。但是为了简化,整个AOP还提供环绕通知,
即一个方法可以处理所有的aop操作,这种操作更像代理结构:
范例:增加环绕处理
但是必须考虑接收参数的情况,而接收的参数类型只能是一种类型:ProceedingJoinPoint,通过此类型可以取得全部的提交参数信息。
public Object serviceAround(ProceedingJoinPoint point) throws Throwable { System.out.println("AOP切面数据层方法调用之前,参数:"+Arrays.toString(point.getArgs())); Member vo=new Member(); vo.setMid("TestAOP"); vo.setName("测试AOP"); Object retVal=point.proceed(new Object[]{ vo }); //retVal接收方法数据层调用之后的结果 System.out.println("AOP切面数据层方法调用之后,返回值:"+retVal); return true; }
在整个环绕拦截之中,用户可以任意修改传递的参数数据,也可以修改返回的结果。
配置环绕拦截:
<aop:around method="serviceAround" pointcut="execution(* com.Spring..*.*(..)))" />
执行结果:
所以,在所有AOP操作中,环绕的功能是最强大的。其他拦截只能做一些信息记录,而环绕可以对传入的参数和返回结果进行控制。
以上是关于18-spring学习-AOP深入操作的主要内容,如果未能解决你的问题,请参考以下文章
曹工说Spring Boot源码(18)-- Spring AOP源码分析三部曲,终于快讲完了 (aop:config完整解析下)