You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SpringCloud多数据源@RefreshScope报错:配置热更新无法执行

Spring Cloud多数据源热更新@RefreshScope报错的解决方案

我之前在做Spring Cloud多数据源热更新配置时踩过几乎一模一样的坑,结合你贴出的代码片段,大概率是这几个核心问题导致的报错:


1. @RefreshScope使用位置错误,且属性绑定方式不对

你注释掉了@ConfigurationProperties,改用手动datasource.setUrl(this.dbUrl)的方式,但this.dbUrl如果不是从可刷新的属性源中获取的,@RefreshScope根本感知不到配置变化;而且直接在DataSource的@Bean方法上加@RefreshScope,会导致有状态的Druid连接池Bean在刷新时出现状态冲突、连接泄漏等问题。

解决办法:封装可刷新的属性类,间接更新DataSource

把数据库配置单独封装成一个带@RefreshScope的内部类,用@ConfigurationProperties绑定配置中心的属性,再通过构造注入到DataSource的创建逻辑中:

@RefreshScope
@Configuration
@MapperScan(basePackages = DruidCrmDBConfig.PACKAGE, sqlSessionFactoryRef = DruidCrmDBConfig.NAME + "SessionFactory")
public class DruidCrmDBConfig {
    public static final String NAME = "crm";
    public static final String PACKAGE = "com.example.mapper.crm";

    // 封装可刷新的数据库属性
    @ConfigurationProperties(prefix = "spring." + NAME)
    @RefreshScope
    @Data // 用Lombok简化getter/setter,没有Lombok就手动写
    public static class CrmDbProperties {
        private String url;
        private String username;
        private String password;
        // 其他Druid需要的配置,比如driverClassName、initialSize等
    }

    private final CrmDbProperties dbProperties;

    // 构造注入属性类(Spring 4.3+支持无@Autowired的构造注入)
    public DruidCrmDBConfig(CrmDbProperties dbProperties) {
        this.dbProperties = dbProperties;
    }

    @Bean(name = NAME + "DataSource")
    public DataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();
        // 从可刷新的属性类中取值
        datasource.setUrl(dbProperties.getUrl());
        datasource.setUsername(dbProperties.getUsername());
        datasource.setPassword(dbProperties.getPassword());
        // 其他Druid配置...
        return datasource;
    }

    // 注意:如果要让SqlSessionFactory也感知数据源变化,需要给它也加@RefreshScope
    @Bean(name = NAME + "SessionFactory")
    @RefreshScope
    public SqlSessionFactory sqlSessionFactory(@Qualifier(NAME + "DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        // 设置mapper.xml路径等必要配置
        return sessionFactory.getObject();
    }
}

2. 多数据源场景下的Bean刷新依赖冲突

如果你的项目中有多个类似的数据源配置类,要确保每个配置类的@RefreshScope只作用于自身的属性和相关Bean,避免跨Bean的刷新干扰。另外,要确保Spring Cloud的刷新机制正常工作:

  • 配置中心(如Nacos/Config Server)的配置已经正确推送
  • 项目中引入了spring-cloud-starter-bootstrap(Spring Cloud 2020+版本需要)
  • 触发刷新的端点(/actuator/refresh)可以正常访问(如果手动触发的话)

3. 常见报错的额外排查点

如果还是报BeanCreationException或连接池相关错误:

  • 检查Druid版本是否兼容Spring Cloud的版本,建议使用最新稳定版
  • 确保旧的DataSource连接池在刷新时能被正确销毁,可以给DruidDataSource设置合理的关闭超时时间
  • 避免在DataSource的Bean中使用静态变量存储配置,静态变量不会随@RefreshScope刷新

内容的提问来源于stack exchange,提问作者mangues

火山引擎 最新活动