内部调用自定义注解方法,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");
    }
}

作者:colfish

出处:https://www.cnblogs.com/colfish/p/17577886.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   colfish  阅读(720)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示