源码学习——配置中心

配置中心代码调用图:


config client入口是PropertySourceBootstrapConfiguration,最终会通过RestTemplate向config server发出http get请求,url包含了client的name、profile及lable信息。config server的EnvironmentController提供了多种参数形式的接口,然后调用EnvironmentRepository的findOne方法,根据client提供的参数获取属于它的配置信息,最终返回Environmen对象。具体代码如下:

PropertySourceBootstrapConfiguration类部分源码:

ConfigServicePropertySourceLocator部分源码:



 EnvironmentController部分源码


剩下就是我们自己的代码了,首先要开启配置中心:

客户端直接在配置文件中开启并指定服务端名字,服务端在入口类加上:

@EnableConfigServer

然后就是实现EnvironmentRepository的findOne方法,如类EnvironmentRepositoryImpl

package com.ConfigServer.environment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import com.ConfigServer.service.ConfigRepositoryService;
public class EnvironmentRepositoryImpl implements EnvironmentRepository{
	/*
	 * 用于标识配置信息从哪里取,如database代表从数据库中取,properties代表从配置文件中取
	 * 为null代表从配置文件和数据库中取,该属性是自己定义的
	 */
	@Value("${spring.cloud.config.server.configSource}")
	private String configSource;
	@Autowired
	private ConfigRepositoryService configRepositoryService;
	/*
	 * 其它服务启动的时该方法会被调用,从而获得属于自己的配置信息
	 */
	@Override
	public Environment findOne(String application, String profile, String label) {
		switch (configSource) {
		case "database":
			return configRepositoryService.getEnvironmentFromDatabaseByMybatis(application, profile, label);
		case "properties":
			return configRepositoryService.getEnvironmentFromProperties(application, profile, label);
		default:
			// TODO 可以把数据库和配置文件并集
			return null;
		}
	}
}

然后要注入EnvironmentRepositoryImpl类:

package com.ConfigServer.config;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.config.server.environment.EnvironmentRepository;
import org.springframework.cloud.config.server.environment.NativeEnvironmentRepository;
import org.springframework.cloud.config.server.environment.SearchPathLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import com.ConfigServer.environment.EnvironmentRepositoryImpl;
@Configuration
public class EnvironmentRepositoryConfiguration {
	@Autowired
	 private ConfigurableEnvironment environment;
	 @Bean
	 public SearchPathLocator searchPathLocator() {
	  return new NativeEnvironmentRepository(environment);
	 }
 
	 /*
	  * Primary与Order都是用来控制当有多个相同bean的实现时,选择哪一个。
	  * @Primary告诉容器该实现的优先级最高,作用与@Order(Ordered.HIGHEST_PRECEDENCE)相同,二选一即可
	  * 值得注意的是,如果Spring Cloud版本是Edgware.RELEASE,使用@Primary启动会报错,此时可以使用Order,
	  * 两者都不用似乎也可以
	  */
	 @Order(Ordered.HIGHEST_PRECEDENCE)
//	 @Primary
	 @Bean
	 public EnvironmentRepository openEnvironmentRepository() {
	  return new EnvironmentRepositoryImpl();
	 }
}

为什么还要注入NativeEnvironmentRepository?有待研究

这里虽然EnvironmentRepositoryImpl的优先级最高,但其依赖ConfigRepositoryService,所以还是会先注入ConfigRepositoryService,该类用于读取配置信息(如从数据库获取):

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.context.EnvironmentAware;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.stereotype.Service;
import com.ConfigServer.entity.NameValuePair;
 
@Service
public class ConfigRepositoryService implements EnvironmentAware{
	private org.springframework.core.env.Environment env;
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	//也可以采用如下方式注入Environment,而不用实现EnvironmentAware
//	@Autowired
//	private ConfigurableEnvironment env;
	
	@Override
	public void setEnvironment(org.springframework.core.env.Environment environment) {
		env = environment;
	}
	public Environment getEnvironmentFromProperties(String application, String profile, String label){
		//如果属性个数很少且名字确定,也可以用@Value的方式注入
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env,application+".");
		Map<String, Object> propertyMap = propertyResolver.getSubProperties(null);
		PropertySource propertySource = new PropertySource("configServer", propertyMap);
		Environment environment = new Environment(application, profile, label, "1.0", null);
		environment.add(propertySource);
		return environment;
	}
 
	public Environment getEnvironmentFromDatabase(String application, String profile, String label) {
		ResultSetExtractor<List<NameValuePair>> rse = new ResultSetExtractor<List<NameValuePair>>() {
			@Override
			public List<NameValuePair> extractData(ResultSet rs) throws SQLException, DataAccessException {
				List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
				while (rs.next()) {
					NameValuePair nameValuePair = new NameValuePair();
					nameValuePair.setName(rs.getString("key"));
					nameValuePair.setValue(rs.getString("value"));
					nameValuePairs.add(nameValuePair);
				}
				return nameValuePairs;
			}
		};
		String sql = "select key , value from config_info where application=?";
		Object[] params = new Object[1];
		params[0] = application;
		List<NameValuePair> nameValuePairs = jdbcTemplate.query(sql, params, rse);
		if(nameValuePairs == null || nameValuePairs.size() == 0)
			return null;
		Map<String, Object> propertyMap = new HashMap<String, Object>();
		for(NameValuePair nameValuePair:nameValuePairs) {
			propertyMap.put(nameValuePair.getName(), nameValuePair.getValue());
		}
		PropertySource propertySource = new PropertySource("configServer", propertyMap);
		Environment environment = new Environment(application, profile, label, "1.0", null);
		environment.add(propertySource);
		return environment;
	}
}
Environment可以add多个propertySource,propertySource的名字仅仅是用于标识这些配置项的来源,可以任意取,比如,属于数据库配置项,我们可以取名oralce.db,属于定时任务的配置项,我们可以取名schedule等等。











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值