Loading

内部调用自定义注解方法,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");
    }
}
posted @ 2023-07-24 17:42  colfish  阅读(891)  评论(0)    收藏  举报