@RefreshScope导致AOP切面重复执行源码分析

前言

公司服务中引入了Nacos做配置中心,通过@RefreshScope注解可实现配置实时刷新。在某个AOP切面中发现使用@RefreshScope后,切面方法重复执行了两次,什么原因导致的呢?我们开始今天的源码分析

Tips:需要spring aop源码基础,否则很难看懂。

测试demo

java 复制代码
@Aspect
@Component
@RefreshScope
public class TestAspect {

    @Value("${abcde.huang}")
    private String name;

    @Pointcut("execution(public * com.ht.service.impl.TestService.sayHelloByName(..))")
    public void sayHelloByName() {
    }

    @Before("sayHelloByName()")
    public void beforeSelect(JoinPoint point) {
        System.out.println("aop"+name);
    }
}
java 复制代码
@Service
public class TestServiceImpl implements TestService {

    @Override
    public String sayHelloByName(String name) {
        return name + ",hello!";
    }
}
java 复制代码
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
       ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
        TestService bean = run.getBean(TestService.class);
       bean.sayHelloByName("test");
    }
}

源码分析

AOP第一次增强,往上看在哪里执行的 这里感觉很诡异,测试demo里只有一处使用了aop,不应该是两个,我们继续往上看,这个List在哪构造的。 继续往上看,重点关注这个this.advised.getInterceptorsAndDynamicInterceptionAdvice方法。 继续往里面看

java 复制代码
private List<Advisor> advisors = new ArrayList<>();
@Override
public final Advisor[] getAdvisors() {
    return this.advisors.toArray(new Advisor[0]);
}
public void addAdvisors(Collection<Advisor> advisors) {
    if (isFrozen()) {
       throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
    }
    if (!CollectionUtils.isEmpty(advisors)) {
       for (Advisor advisor : advisors) {
          if (advisor instanceof IntroductionAdvisor) {
             validateIntroductionAdvisor((IntroductionAdvisor) advisor);
          }
          Assert.notNull(advisor, "Advisor must not be null");
          this.advisors.add(advisor);
       }
       adviceChanged();
    }
}

到这里问题已经很清楚了,spring中存在两个"testAspect"bean,导致aop责任链重复执行切面方法。 这里也进一步验证了前面的分析。

总结

当我们在实际项目中遇到问题时,往往并不清楚问题的关键所在。本文采用打断点的方法,逐层从下而上分析源代码,以找出问题的根源。

当切面类TestAspect(加了@Aspect)加上@RefreshScope时后会生成scopedTarget.testAspect和testAspect两个bean,造成切面方法执行两次。具体@RefreshScope为什么会额外生成scopedTarget.testAspect这个bean,我将在另一篇文章中解析。

相关推荐
蓝斯4973 小时前
[原创]《C#高级GDI+实战:从零开发一个流程图》第章:增加贝塞尔曲线,上、下、左、右连接点
java·c#·流程图
前端工作日常3 小时前
我学习到的Java 的 Service 分层:itf 和 impl 到底是什么?
java·后端
都叫我大帅哥4 小时前
Spring @Transactional 注解完全指南
java·spring
Java成神之路-4 小时前
G1 垃圾回收器 :SATB + TAMS核心机制深度解析
java·jvm
前端工作日常4 小时前
我学习到的JIT即时编译与机器码缓存失效
java·后端
带刺的坐椅5 小时前
Solon 的 10 种 HTTP 服务器:改一行依赖,换一个引擎
java·solon·jetty·undertow·mcp-server·htttp
犀利豆5 小时前
Claude Code Tools 研究系列(三)ExitPlanMode
人工智能·后端
星栈5 小时前
oh-my-pi工程级AI编码工使用体验
人工智能·后端·agent
xcLeigh5 小时前
Go入门:变量声明的五种方式详解
java·开发语言·golang
AI大模型-小华6 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro