SpringBoot项目中使用AOP的方法
本文介绍了springboot项目中使用aop的方法,分享给大家,具体如下:
1.概述
将通用的逻辑用aop技术实现可以极大的简化程序的编写,例如验签、鉴权等。spring的声明式事务也是通过aop技术实现的。
具体的代码参照 示例项目
spring的aop技术主要有4个核心概念:
pointcut: 切点,用于定义哪个方法会被拦截,例如 execution(* cn.springcamp.springaop.service.*.*(..))
advice: 拦截到方法后要执行的动作
aspect: 切面,把pointcut和advice组合在一起形成一个切面
join point: 在执行时pointcut的一个实例
weaver: 实现aop的框架,例如 aspectj 或 spring aop
2. 切点定义
常用的pointcut定义有 execution 和 @annotation 两种。execution 定义对方法无侵入,用于实现比较通用的切面。@annotation 可以作为注解加到特定的方法上,例如spring的transaction注解。
execution切点定义应该放在一个公共的类中,集中管理切点定义。
示例:
public class commonjoinpointconfig { @pointcut("execution(* cn.springcamp.springaop.service.*.*(..))") public void servicelayerexecution() {} }
这样在具体的aspect类中可以通过 commonjoinpointconfig.servicelayerexecution()来引用切点。
public class beforeaspect { @before("commonjoinpointconfig.servicelayerexecution()") public void before(joinpoint joinpoint) { system.out.println(" -------------> before aspect "); system.out.println(" -------------> before execution of " + joinpoint); } }
当切点需要改变时,只需修改commonjoinpointconfig类即可,不用修改每个aspect类。
3. 常用的切面
before: 在方法执行之前执行advice,常用于验签、鉴权等。
after: 在方法执行完成后执行,无论是执行成功还是抛出异常.
afterreturning: 仅在方法执行成功后执行.
afterthrowing: 仅在方法执抛出异常后执行.
一个简单的aspect:
@aspect @component public class beforeaspect { @before("commonjoinpointconfig.servicelayerexecution()") public void before(joinpoint joinpoint) { system.out.println(" -------------> before aspect "); system.out.println(" -------------> before execution of " + joinpoint); } }
4. 自定义注解
假设我们想收集特定方法的执行时间,一种比较合理的方式是自定义一个注解,然后在需要收集执行时间的方法上加上这个注解。
首先定义一个注解tracktime:
@target({elementtype.method, elementtype.type}) @retention(retentionpolicy.runtime) public @interface tracktime { string param() default ""; }
然后再定义一个aspect类,用于实现注解的行为:
@aspect @component public class tracktimeaspect { @around("@annotation(tracktime)") public object around(proceedingjoinpoint joinpoint, tracktime tracktime) throws throwable { object result = null; long starttime = system.currenttimemillis(); result = joinpoint.proceed(); long timetaken = system.currenttimemillis() - starttime; system.out.println(" -------------> time taken by " + joinpoint + " with param[" + tracktime.param() + "] is " + timetaken); return result; } }
在某个方法上使用这个注解,就可以收集这个方法的执行时间:
@tracktime(param = "myservice") public string runfoo() { system.out.println(" -------------> foo"); return "foo"; }
注意 @tracktime(param = "myservice") 注解是可以传参的。
为了让注解可以传参数,需要在定义注解时指定一个参数string param() default "默认值",
同时在aspect类中,around方法上加上相应的参数,@around注解中也需要用参数的变量名tracktime,而不能用类名tracktime。
@around("@annotation(tracktime)") public object around(proceedingjoinpoint joinpoint, tracktime tracktime)
5.总结
在运行示例项目时,控制台会输出以下内容:
-------------> before aspect
-------------> before execution of execution(string cn.springcamp.springaop.service.myservice.runfoo())
-------------> foo
-------------> time taken by execution(string cn.springcamp.springaop.service.myservice.runfoo()) with param[myservice] is 8
-------------> after aspect
-------------> after execution of execution(string cn.springcamp.springaop.service.myservice.runfoo())
-------------> afterreturning aspect
-------------> execution(string cn.springcamp.springaop.service.myservice.runfoo()) returned with value foo
可以看出几种 aspect 的执行顺序依次为 before after around afterreturning(afterthrowing)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。