准备工作
首先,使用AOP要在build.gradle中加入依赖
//引入AOP依赖
compile "org.springframework.boot:spring-boot-starter-aop:${springBootVersion}"
然后在application.yml中加入
spring:
aop:
proxy-target-class: true
1.@Pointcut 切入点
定义一个切点。
例如我们要在一个方法加上切入点,根据方法的返回的对象,方法名,修饰词来写成一个表达式或者是具体的名字
我们现在来定义一个切点
package com.example.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 类定义为切面类
*/
@Aspect
@Component
publicclassAopTestController{
privatestaticfinalLogger logger =LoggerFactory.getLogger(AopTestController.class);
/**
* 定义一个切点
*/
@Pointcut(value ="execution(public String test (..))")
publicvoid cutOffPoint(){
}
}
这里的切点定义的方法是
@GetMapping("hello")
publicString test(){
logger.info("欢迎关注Java知音");
return"i love java";
}
如果你想写个切入点在所有返回对象为Area的方法,如下
@Pointcut("execution(public com.example.entity.Area (..))")
等很多写法,也可以直接作用在某些包下
注意:private修饰的无法拦截
2.@Before前置通知
在切入点开始处切入内容
在之前的AopTestController类中加入对test方法的前置通知
@Before("cutOffPoint()")
publicvoid beforeTest(){
logger.info("我在test方法之前执行");
}
这里@Before里的值就是切入点所注解的方法名
在方法左侧出现的图标跟过去以后就是所要通知的方法 这里就是配置正确了,我们来浏览器调用一下方法
联想一下,这样的效果可以用在哪里,想像如果要扩展一些代码,在不需要动源代码的基础之上就可以进行拓展,美滋滋
3.@After 后置通知
和前置通知相反,在切入点之后执行
@After("cutOffPoint()")
publicvoid doAfter(){
logger.info("我是在test之后执行的");
}
控制台执行结果
这里定义一个通知需要重启启动类,而修改通知方法的内容是可以热部署的
4.@Around环绕通知
和前两个写法不同,实现的效果包含了前置和后置通知。
当使用环绕通知时,proceed方法必须调用,否则拦截到的方法就不会再执行了
环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的
ThreadLocal<Long> startTime =newThreadLocal<>();
@Around("cutOffPoint()")
publicObject doAround(ProceedingJoinPoint pjp){
startTime.set(System.currentTimeMillis());
logger.info("我是环绕通知执行");
Object obj;
try{
obj = pjp.proceed();
logger.info("执行返回值 : "+ obj);
logger.info(pjp.getSignature().getName()+"方法执行耗时: "+(System.currentTimeMillis()- startTime.get()));
}catch(Throwable throwable){
obj=throwable.toString();
}
return obj;
}
执行结果:
1.环绕通知可以项目做全局异常处理
2.日志记录
3.用来做数据全局缓存
4.全局的事物处理 等