详解spring cloud config实现datasource的热部署
程序员文章站
2023-12-10 14:24:34
关于spring cloud config的基本使用,前面的博客中已经说过了,如果不了解的话,请先看以前的博客
spring cloud config整合gitlab...
关于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<collection<string>> { private contextrefresher contextrefresher; public refreshendpoint(contextrefresher contextrefresher) { super("refresh"); this.contextrefresher = contextrefresher; } @managedoperation public string[] refresh() { set<string> keys = contextrefresher.refresh(); return keys.toarray(new string[keys.size()]); } @override public collection<string> invoke() { return arrays.aslist(refresh()); } }
从上面的源码,我们可以看到,重点在contextrefresher这个类上,由于这个类太长了,下面把这个类的部分源码贴出来:
private refreshscope scope; public contextrefresher(configurableapplicationcontext context, refreshscope scope) { this.context = context; this.scope = scope; } public synchronized set<string> refresh() { map<string, object> before = extract( this.context.getenvironment().getpropertysources());// 1、before,加载提取配置文件 addconfigfilestoenvironment();// 2、将配置文件加载到环境中 set<string> keys = changes(before, extract(this.context.getenvironment().getpropertysources())).keyset();// 3、替换原来环境变量中的值 this.context.publishevent(new environmentchangeevent(keys));// 4、发布变更事件, this.scope.refreshall(); return keys; }
从上面的代码不难看出,重点经历了4个步骤,上面代码中已标注。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。