Nacos+SpringBoot 实现动态修改数据库地址而不用重启
Nacos+SpringBoot 动态修改数据源
·
前一阵子,服务器出现了问题,导致数据库需要更换地址,业务服不能做到不停机更换,经过这次事件我便开始着手研究如何让服务不重启更换数据库。监听nacos的配置修改+druid 配置多数据源 可以实现。
一、前置准备:druid 配置多数据源
DruidConfig
@Configuration
public class DruidConfig
{
@Bean
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource masterDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slaveDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource)
{
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
return new DynamicDataSource(masterDataSource, targetDataSources);
}
/**
* 设置数据源
*
* @param targetDataSources 备选数据源集合
* @param sourceName 数据源名称
* @param beanName bean名称
*/
public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
{
try
{
DataSource dataSource = SpringUtils.getBean(beanName);
targetDataSources.put(sourceName, dataSource);
}
catch (Exception e)
{
}
}
/**
* 去除监控页面底部的广告
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
@ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
{
// 获取web监控页面的参数
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
// 提取common.js的配置路径
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
final String filePath = "support/http/resources/js/common.js";
// 创建filter进行过滤
Filter filter = new Filter()
{
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
chain.doFilter(request, response);
// 重置缓冲区,响应头不会被重置
response.resetBuffer();
// 获取common.js
String text = Utils.readFromResource(filePath);
// 正则替换banner, 除去底部的广告信息
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
text = text.replaceAll("powered.*?shrek.wang</a>", "");
response.getWriter().write(text);
}
@Override
public void destroy()
{
}
};
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns(commonJsPattern);
return registrationBean;
}
}
如上所示,把数据源交给Druid管理,后续naocs监听类会注入你所要修改的数据源。
Restart
@Configuration
@RefreshScope
@Data
@Slf4j
public class DruidDataSourceRestart {
@Value("${spring.application.name}")
private String appName;
@Value("${spring.profiles.active}")
private String env;
@Autowired
private NacosConfigProperties nacosConfigProperties;
// 这里注入你要修改的数据源,也可以注入多个,下面监听处理
@Resource(name = "masterDataSource")
private DruidDataSource dataSource;
@PostConstruct
public void init() {
try {
log.info("nacos监听启动,当前环境:" + appName + "-" + env + ".yml" + ",分组:" + nacosConfigProperties.getGroup());
nacosConfigProperties.configServiceInstance().addListener(appName + "-" + env + ".yml", nacosConfigProperties.getGroup(), new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String s) {
Map master = null;
try {
Yaml yaml = new Yaml();
Map map = (Map) yaml.load(s);
Map spring = (Map) map.get("spring");
Map datasource = (Map) spring.get("datasource");
Map dynamic = (Map) datasource.get("dynamic");
Map dynamicDatasource = (Map) dynamic.get("datasource");
master = (Map) dynamicDatasource.get("master");
} catch (Exception e) {
log.error("监听解析nacos返回的配置信息出错", e.getMessage());
return;
}
System.out.println("最新的master配置信息:" + master);
Boolean newMaster = true;
//这里拿到最新的配置信息,通过对比旧的配置信息决定是否更新数据库信息
// xxxxxxxx
// xxxxxxxx newMaster = xx;
if (newMaster) {
try {
dataSource.restart();
dataSource.setUrl("新的url");
dataSource.setUsername("新的用户名");
dataSource.setPassword("新的密码");
dataSource.setDriverClassName("新的驱动名");
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
});
} catch (NacosException e) {
log.error("监听nacos配置错误");
throw new RuntimeException(e);
}
}
}
通过上述代码便可服务不重启达成更改数据库信息的效果,上面只处理了主数据源,网友们也可以继续处理其他数据源。欢迎点赞收藏。
更多推荐


所有评论(0)