详解spring cloud config实现datasource的热部署

网友投稿 554 2023-02-26


详解spring cloud config实现datasource的热部署

关于spring cloud config的基本使用,前面的博客中已经说过了,如果不了解的话,请先看以前的博客

spring cloud config整合gitlab搭建分布式的配置中心

spring cloud config分布式配置中心的高可用

今天,我们的重点是如何实现数据源的热部署。

1、在客户端配置数据源

@RefreshScope

@Configuration// 配置数据源

public class DataSourceConfigure {

@Bean

@RefreshScope// 刷新配置文件

@ConfigurationProperties(prefix="spring.datasource") // 数据源的自动配置的前缀

public DataSource dataSource(){

return DataSourceBuilder.create().build();

}

}

通过上面的几个步骤,就可以实现在gitlab上修改配置文件,刷新后,服务器不用重启,新的数据源就会生效。

2、自定义数据源的热部署

当我们使用spring boot集成druid,我们需要手动来配置数据源,代码如下:

package com.chhliu.springcloud.config;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.cloud.context.config.annotation.RefreshScope;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.Primary;

import com.alibaba.druid.pool.DruidDataSource;

import lombok.extern.slf4j.Slf4j;

/**

*

* 描述:如果不使用代码手动初始化DataSource的话,监控界面的SQL监控会没有数据("是spring boot的bug???")

* @author chhliu

* 创建时间:2017年2月9日 下午7:33:08

* @version 1.2.0

*/

@Slf4j

@Configuration

@RefreshScope

public class DruidConfiguration {

@Value("${spring.datasource.url}")

private String dbUrl;

@Value("${spring.datasource.username}")

private String username;

@Value("${spring.datasource.password}")

private String password;

@Value("${spring.datasource.driverClassName}")

private String driverClassName;

@Value("${spring.datasource.initialSize}")

private int initialSize;

@Value("${spring.datasource.minIdle}")

private int minIdle;

@Value("${spring.datasource.maxActive}")

private int maxActive;

@Value("${spring.datasource.maxWait}")

private int maxWait;

@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")

private int timeBetweenEvictionRunsMillis;

@Value("${spring.datasource.minEvictableIdleTimeMillis}")

private int minEvictableIdleTimeMillis;

@Value("${spring.datasource.validationQuery}")

private String validationQuery;

@Value("${spring.datasource.testWhileIdle}")

private boolean testWhileIdle;

@Value("${spring.datasource.testOnBorrow}")

private boolean testOnBorrow;

@Value("${spring.datasource.testOnReturn}")

private boolean testOnReturn;

@Value("${spring.datasource.poolPreparedStatements}")

private boolean poolPreparedStatements;

@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")

private int maxPoolPreparedStatementPerConnectionSize;

@Value("${spring.datasource.filters}")

private String filters;

@Value("${spring.datasource.connectionProperties}")

private String connectionProperties;

@Value("${spring.datasource.useGlobalDataSourceStat}")

private boolean useGlobalDataSourceStat;

@Bean //声明其为Bean实例

@Primary //在同样的DataSource中,首先使用被标注的DataSource

@RefreshScope

public DataSource dataSource(){

DruidDataSource datasource = new DruidDataSource();

datasource.setUrl(this.dbUrl);

datasource.setUsername(username);

datasource.setPassword(password);

datasource.setDriverClassName(driverClassName);

//configuration

datasource.setInitialSize(initialSize);

datasource.setMinIdle(minIdle);

datasource.setMaxActive(maxActive);

datasource.setMaxWait(maxWait);

datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);

datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);

datasource.setValidationQuery(validationQuery);

datasource.setTestWhileIdle(testWhileIdle);

datasource.setTestOnBorrow(testOnBorrow);

datasource.setTestOnReturn(testOnReturn);

datasource.setPoolPreparedStatements(poolPreparedStatements);

datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);

datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);

try {

datasource.setFilters(filters);

} catch (SQLException e) {

log.error("druid configuration initialization filter: "+ e);

}

datasource.setConnectionProperties(connectionProperties);

return datasource;

}

}

通过上面的示例,也可以实现数据源的动态刷新。接下来,我们就来看看,spring cloud config是怎么来实现数据源的热部署的。

从前面的博客中,我们不难发现,要想实现动态刷新,关键点就在post refresh的请求上,那我们就从刷新配置文件开始。

当我们post刷新请求的时候,这个请求会被actuator模块拦截,这点从启动的日志文件中就可以看出

复制代码 代码如下:

Mapped "{[/refresh || /refresh.json],methods=[POST]}" onto public java.lang.Object org.springframework.cloud.endpoint.GenericPostableMvcEndpoint.invoke()

接下来,我们就来看actuator定义的EndPoint,然后我们就找到了RefreshEndpoint这个类,该类的源码如下:

@ConfigurationProperties(prefix = "endpoints.refresh", ignoreUnknownFields = false)

@ManagedResource

public class RefreshEndpoint extends AbstractEndpoint> {

private ContextRefresher contextRefresher;

public RefreshEndpoint(ContextRefresher contextRefresher) {

super("refresh");

this.contextRefresher = contextRefresher;

}

@ManagedOperation

public String[] refresh() {

Set keys = contextRefresher.refresh();

return keys.toArray(new String[keys.siztWBYGCJe()]);

}

@Override

public Collection invoke() {

return Arrays.asList(refresh());

}

}

从上面的源码,我们可以看到,重点在ContextRefresher这个类上,由于这个类太长了,下面把这个类的部分源码贴出来:

tWBYGCJ

private RefreshScope scope;

public ContextRefresher(ConfigurableApplicationContext context, RefreshScope scope) {

this.context = context;

this.scope = scope;

}

public synchronized Set refresh() {

Map before = extract(

this.context.getEnvironment().getPropertySources());// 1、before,加载提取配置文件

addConfigFilesToEnvironment();// 2、将配置文件加载到环境中

Set keys = changes(before,

extract(this.context.getEnvironment().getPropertySources())).keySet();// 3、替换原来环境变量中的值

this.context.publishEvent(new EnvironmentChangeEvent(keys));// 4、发布变更事件,

this.scope.refreshAll();

return keys;

}

从上面的代码不难看出,重点经历了4个步骤,上面代码中已标注。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:添加购物车接口测试用例(购物车api接口测试点)
下一篇:详解layui中的树形关于取值传值问题
相关文章

 发表评论

暂时没有评论,来抢沙发吧~