分布式配置

文章目录
  1. 1. 分布式配置
  2. 2. 客户端
  3. 3. 服务端
  4. 4. 客户端流程分析
  5. 5. 服务端流程分析
分布式配置

相关产品
国内:Disconf(百度) Apollo(携程) Nacos(阿里)
国外: Spring-Cloud-Config Netfix Archaius

客户端
// 关于配置项的刷新->主动刷新(拉的模式)
1. 客户端可以通过接口 http://127.0.0.1:8082/actuator/refresh 来主动刷新配置(post方法) ,但是该接口的调用需要修改配置文件里面的值。
management.endpoint.refresh.enabled=true
2. 当配置项发生变化时,bean里面引用的配置项并未发生变化。需要使用 @RefreshScope 注解来标记,只有使用该注解标记的类,当配置项发生变化时,引用的配置项才会发生变化。
@RestController
@RefreshScope// (开关 阈值 文案等配置,其它配置可以重启服务器)
public class EchoController {

@Value("${my.name}")
private String myName = "jack-1";

@GetMapping("/myName")
public String getMyName() {
return myName;
}
}
3. 可以配置定时器来每隔指定的时间去主动刷新配置
@SpringBootApplication
@EnableScheduling // 开启定时任务
public class ConfigClientApp {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApp.class, args);
}

// 定时刷新配置
private final ContextRefresher contextRefresher;

private final Environment environment;

public ConfigClientApp(ContextRefresher contextRefresher, Environment environment) {
this.contextRefresher = contextRefresher;
this.environment = environment;
}

// 配置定时器每隔5秒刷新一次配置项
@Scheduled(fixedRate = 5 * 1000, initialDelay = 3 * 1000)
public void autoRefresh() {
Set<String> updatedPropertyNames = contextRefresher.refresh();
updatedPropertyNames.forEach( propertyName ->
System.err.printf(
"[Thread :%s] 当前配置已更新,具体 Key:%s , Value : %s \n",
Thread.currentThread().getName(),
propertyName,
environment.getProperty(propertyName)
)
);
}
}
服务端
@EnableAutoConfiguration
@Configuration
@ComponentScan
// 激活配置管理服务器
@EnableConfigServer
public class ConfigServerApp {

public static void main(String[] args) {
SpringApplication.run(ConfigServerApp.class, args);
}

/**
* 自定义配置实现,绕过git实现
* @return
*/
@Bean
public EnvironmentRepository environmentRepository() {
return (String application, String profile, String label) -> {
Environment environment = new Environment("default", profile);
List<PropertySource> propertySources = environment.getPropertySources();
Map<String, Object> source = new HashMap<String, Object>();
source.put("name", "微服务->long");
PropertySource propertySource = new PropertySource("map", source);
propertySources.add(propertySource);
return environment;
};
}
}
客户端流程分析
/*
1. 在客户端,我们可以配置形如: localhost:8080/{name}/{profiles}/{label} 去从服务端获取配置。
2. 在服务端是通过 EnvironmentController 类来对外提供服务的。
*/
@RestController
@RequestMapping(method = RequestMethod.GET, path = "${spring.cloud.config.server.prefix:}")
public class EnvironmentController {

@RequestMapping("/{name}/{profiles}/{label:.*}")
public Environment labelled(@PathVariable String name, @PathVariable String profiles,
@PathVariable String label) {
if (name != null && name.contains("(_)")) {
// "(_)" is uncommon in a git repo name, but "/" cannot be matched
// by Spring MVC
name = name.replace("(_)", "/");
}
if (label != null && label.contains("(_)")) {
// "(_)" is uncommon in a git branch name, but "/" cannot be matched
// by Spring MVC
label = label.replace("(_)", "/");
}
Environment environment = this.repository.findOne(name, profiles, label);
if (!this.acceptEmpty
&& (environment == null || environment.getPropertySources().isEmpty())) {
throw new EnvironmentNotFoundException("Profile Not found");
}
return environment;
}
}
服务端流程分析
/*
1. 在 @EnableConfigServer 注解中使用了 @Import 注解导入了配置类 ConfigServerConfiguration。
2. 在配置类 ConfigServerConfiguration 上面使用 @Configuration 注解表明该类是一个配置类,该配置类
会在上下文中创建一个类型为 ConfigServerConfiguration.Marker 的bean。
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ConfigServerConfiguration.class)
public @interface EnableConfigServer {

}
@Configuration
public class ConfigServerConfiguration {
@Bean
public Marker enableConfigServerMarker() {
return new Marker();
}
class Marker {}
}
/*
1. ConfigServerAutoConfiguration 类上面使用了 @ConditionalOnBean 注解,只有当上下文中存在类型
为 ConfigServerConfiguration.Marker 的bean时,才会执行该配置类的流程(条件装配)。
2. 在该类中导入了一些配置类,EnvironmentRepositoryConfiguration 等这些类会根据条件判断创建相关的
bean。
*/
@Configuration // 配置类
@ConditionalOnBean(ConfigServerConfiguration.Marker.class) // 条件装配
@EnableConfigurationProperties(ConfigServerProperties.class)
@Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class,
ResourceRepositoryConfiguration.class, ConfigServerEncryptionConfiguration.class,
ConfigServerMvcConfiguration.class })
public class ConfigServerAutoConfiguration {

}
/*
1. EnvironmentRepositoryConfiguration 通过 @Import 注解导入了一些相关的配置类。
JdbcRepositoryConfiguration GitRepositoryConfiguration 分别时基于jdbc和git实现配置
的仓储。
2. GitRepositoryConfiguration 继承啦 DefaultRepositoryConfiguration 类,属于默认实现。
3. 在 DefaultRepositoryConfiguration 类中 通过 @ConditionalOnMissingBean 注解表明当前
上下文中若是没有 EnvironmentRepository 类型的bean存在时,会创建一个类型为
MultipleJGitEnvironmentRepository 的bean
*/
// EnvironmentRepositoryConfiguration 配置
@Configuration
@EnableConfigurationProperties({ SvnKitEnvironmentProperties.class,
CredhubEnvironmentProperties.class, JdbcEnvironmentProperties.class,
NativeEnvironmentProperties.class, VaultEnvironmentProperties.class })
@Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class,
VaultConfiguration.class, VaultRepositoryConfiguration.class,
CredhubConfiguration.class, CredhubRepositoryConfiguration.class,
SvnRepositoryConfiguration.class, NativeRepositoryConfiguration.class,
GitRepositoryConfiguration.class, DefaultRepositoryConfiguration.class })
public class EnvironmentRepositoryConfiguration {

}

// GitRepositoryConfiguration git实现的配置,继承了 DefaultRepositoryConfiguration 默认实现
@Configuration
@Profile("git")
class GitRepositoryConfiguration extends DefaultRepositoryConfiguration {

}
// JdbcRepositoryConfiguration jdbc实现的配置
@Configuration
@Profile("jdbc")
@ConditionalOnClass(JdbcTemplate.class)
class JdbcRepositoryConfiguration {
@Bean
@ConditionalOnBean(JdbcTemplate.class)
public JdbcEnvironmentRepository jdbcEnvironmentRepository(
JdbcEnvironmentRepositoryFactory factory,
JdbcEnvironmentProperties environmentProperties) {
return factory.build(environmentProperties);
}
}

@Configuration
@ConditionalOnMissingBean(value = EnvironmentRepository.class, search = SearchStrategy.CURRENT)
class DefaultRepositoryConfiguration {
@Bean
public MultipleJGitEnvironmentRepository defaultEnvironmentRepository(
MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory,
MultipleJGitEnvironmentProperties environmentProperties) throws Exception {
return gitEnvironmentRepositoryFactory.build(environmentProperties);
}
}
/*
到此,还有一个问题,那就是 ConfigServerAutoConfiguration 时如何加载的,通过相关jar包里面的
spring.factories 文件可以看到 ConfigServerAutoConfiguration 被 EnableAutoConfiguration
通过spring的spi加载。
*/
# Autoconfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.config.server.config.ConfigServerAutoConfiguration,\
org.springframework.cloud.config.server.config.EncryptionAutoConfiguration