AOP为何失效?
请看以下代码
service
@Service
public class HelloBbService {
public void hello1() {
System.out.println("how are you ?");
// 通过this调用
this.hello2();
}
public void hello2() {
System.out.println("what's your name?");
}
}
aop设置
@Aspect
@Component
@Slf4j
public class AopConfig {
@Around("execution(* cn.bb.mydemo.service.HelloBbService.hello2()) ")
public void printLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("方法执行开始");
joinPoint.proceed();
log.info("方法执行结束");
}
}
控制层
@RestController
public class HelloBbController {
@Autowired
private HelloBbService helloBbService;
@GetMapping(path = "hellobb")
public void hellobb() {
helloBbService.hello1();
}
}
通过调用 输出如下
how are you ?
what's your name?
问题原因
通过断点发现,通过this拿到的对象只是普通对象,而只有代理对象,才能够被Spring增强,使得Aop生效。
问题解决
1. 使用@Autowired 自我注入
不是要代理对象嘛,通过@Autowired
注入的方式拿到的就是代理对象,代码修改如下。
@Service
public class HelloBbService {
@Autowired
private HelloBbService helloBbService;
public void hello1() {
System.out.println("how are you ?");
// 通过this调用
helloBbService.hello2();
}
public void hello2() {
System.out.println("what's your name?");
}
}
方法调用输出如下。
可以看到,aop生效了。
这里要复习下。
jdk动态代理,只能针对实现类生成代理。
cglib动态代理,能针对普通类生成代理。
这里我并没有用接口实现,所以会使用cglib代理。
但是这种方式我并不推荐,为什么?因为当注入的类多时,会存在循环依赖的问题。
2.使用AopContext.currentProxy()
这才是这篇文章的重点,有同学说AopContext
是什么?
它提供了一种在运行时获取当前代理对象的机制。通过AopContext,可以在实例化类时直接获取当前代理对象,而无需传递代理对象的引用。
本质上,它通过ThreadLocal 来将 Proxy 和线程绑定起来,这样就可以随时拿出当前线程绑定的 Proxy。
但注意,它默认是被禁用的,需要开启后才能使用。
可以通过该注解开启@EnableAspectJAutoProxy(exposeProxy = true)
代码修改如下。
@Service
@EnableAspectJAutoProxy(exposeProxy = true)// 为了方便 暂时加在了这里 建议大家加在启动类上
public class HelloBbService {
public void hello1() {
System.out.println("how are you ?");
HelloBbService helloBbService = (HelloBbService) AopContext.currentProxy();
helloBbService.hello2();
}
public void hello2() {
System.out.println("what's your name?");
}
}
再查看下对象,发现确实是代理对象了。
输出如下
从心理学的角度分析,越是头脑简单的人越是需要点缀和填充,而头脑复杂的人则对简洁有着特殊的心理需求。