内部调用自定义注解方法,AOP不生效
之前遇到过的@CacheEvict注解和@Transactional注解内部调用不生效,也是同样的原因
自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
String value();
}
自定义切面
@Slf4j
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(targetDataSource))")
public void switchDataSource(JoinPoint point, TargetDataSource targetDataSource) {
log.info("something to do before...")
}
@After("@annotation(targetDataSource))")
public void restoreDataSource(JoinPoint point, TargetDataSource targetDataSource) {
log.info("something to do after...")
}
}
问题代码
@Slf4j
@Component
public class TestRunner implements CommandLineRunner {
@Override
public void run(String... args) {
query();
}
@TargetDataSource("brf")
public void query() {
log.info("query");
}
}
执行现象
只打印出了query,没有触发AOP逻辑,切面中环绕代码没有执行
原因
这是由于 Spring AOP (包括动态代理和 CGLIB 的 AOP) 并不是扩展了一个类(目标对象(Target Object)), 而是使用了一个代理对象(AOP Proxy Object)来包装目标对象, 并拦截目标对象的方法调用. 导致在目标对象中调用自己类内部实现的方法时, 这些调用并不会转发到代理对象中.
在调用query()时,此时的调用者已经是目标对象了,不会再执行代理对象的AOP逻辑了。
解决方案
1. 注入代理对象调用目标方法
@Slf4j
@Service
public class TestRunner implements CommandLineRunner {
@Autowired
private TestRunner testRunner;
@Override
public void run(String... args) {
testRunner.query();
}
@TargetDataSource("brf")
public void query() {
log.info("query");
}
}
不过会出现循环依赖问题
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
可以增加配置,解决该错误
spring:
main:
allow-circular-references: true
2. 将目标方法写到别的类中,不再内部调用
比较常规,就不写代码举例了
3. 使用@Lazy延迟加载bean
@Slf4j
@Service
public class TestRunner implements CommandLineRunner {
@Lazy
@Autowired
private TestRunner testRunner;
@Override
public void run(String... args) {
testRunner.query();
}
@TargetDataSource("brf")
public void query() {
log.info("query");
}
}

浙公网安备 33010602011771号