Regarding the basic use of spring cloud config, it has been mentioned in the previous blog. If you don’t understand, please read the previous blog first.
Spring cloud config integrates gitlab to build a distributed configuration center
High availability of spring cloud config distributed configuration center
Today, our focus is on how to achieve hot deployment of data sources.
1. Configure the data source on the client
@RefreshScope @Configuration// Configure data source public class DataSourceConfigure { @Bean @RefreshScope// Refresh configuration file @ConfigurationProperties(prefix="spring.datasource") // Prefix for automatic configuration of data source public DataSource dataSource(){ return DataSourceBuilder.create().build(); } } Through the above steps, you can modify the configuration file on gitlab. After refreshing, the server does not need to be restarted, and the new data source will take effect.
2. Hot deployment of custom data sources
When we use spring boot to integrate druid, we need to manually configure the data source, the code is as follows:
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; /** * * Description: If the DataSource is not manually initialized using code, the SQL monitoring of the monitoring interface will have no data ("is a spring boot bug???") * @author chhliu * Created: February 9, 2017 at 7:33:08 pm * @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.testOnBorrow}") private boolean testOnReturn; @Value("${spring.datasource.testOnBorrow}") 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 //Declare it as a Bean instance @Primary //In the same DataSource, first use the annotated 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; } } Through the above example, dynamic refresh of data sources can also be achieved. Next, let’s take a look at how spring cloud config implements hot deployment of data sources.
From the previous blog, it is not difficult to find that in order to achieve dynamic refresh, the key point is on the request of post refresh, so we start by refreshing the configuration file.
When we post refresh request, the request will be intercepted by the actuator module. This can be seen from the startup log file
The code copy is as follows:
Mapped "{[/refresh || /refresh.json],methods=[POST]}" onto public java.lang.Object org.springframework.cloud.endpoint.GenericPostableMvcEndpoint.invoke()
Next, let's look at the EndPoint defined by actuator, and then we find the RefreshEndpoint class. The source code of this class is as follows:
@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()); } }From the above source code, we can see that the focus is on the ContextRefresher class. Since this class is too long, the following is a partial source code of this class:
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, load and extract configuration file addConfigFilesToEnvironment();// 2. Load the configuration file into the environment Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();// 3. Replace the value in the original environment variable this.context.publishEvent(new EnvironmentChangeEvent(keys));// 4. Publish the change event, this.scope.refreshAll(); return keys; } It is not difficult to see from the above code that the key points have gone through 4 steps and have been marked in the above code.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.