配置中心用来集中管理应用不同环境(dev、qa、production)、不同集群的配置,配置修改后能够实时推送到应用端。
| 名称 | 介绍 | 特点 |
| 淘宝(Diamond) | [http://code.taobao.org/svn/diamond/trun] | 配置实时生效,只支持java |
| 百度(Disconf) | [https://github.com/knightliao/disconf] | 配置实时生效,只支持java |
| 携程(Apollo) | [https://github.com/ctripcorp/apollo] | 配置实时生效,支持java、.Net |
| 360(QConf) | [https://github.com/Qihoo360/QConf] | 配置实时生效,支持c/c++、shell、php、python、lua、java、go、node 等语言 |
| (Spring Cloud Config) | [http://cloud.spring.io/spring-cloud-config/] | Spring 配置管理基于git,配置修改后不生效 |
相较于其他几种配置中心服务,spring cloud config实现比较简单,可以基于git/svn/vault这些版本控制服务提供配置的版本化管理,使用也很简单,跟spring生态紧密结合。缺点是没有配置管理界面,并且刷新需要手动请求endpoint,没有公共配置功能。
基于以上不足做了相应的扩展
默认启动非常简单
public static void main(String[] args) {
SpringApplication.run(Application.class, args); //Application为当前main启动类
}
run这个静态方法会构造SpringApplication实例并初始化一些属性:
把参数sources设置到SpringApplication属性中,这个sources可以是任何类型的参数。本文的例子中这个sources就是Application的class对象 spring boot会通过BeanDefinitionLoader根据source的不同类型加载sources
可以通过SpringApplicationBuilder自定义配置进行启动(可以设置main启动类、是否web、设置environment、初始化器、监听器等等):
new SpringApplicationBuilder(ConfigClientApplication.class).main(ConfigClientApplication.class)
.web(true).environment(new StandardEnvironment()).initializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
System.out.println("initialize");
}
}).listeners(new ApplicationListener<ApplicationEvent>() {
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println(applicationEvent);
}
}).build().run(args);
之后会通过SpringApplication的实例方法run启动应用:
启动过程中有几个节点:
本文主要讲应用的配置加载过程,来看看加载environment的过程:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
if(this.isWebEnvironment(environment) && !this.webEnvironment) {
environment = this.convertToStandardEnvironment(environment);
}
return environment;
}
首先创建environment对象,根据是否web应用会创建StandardEnvironment(非web)、StandardServletEnvironment(web),environment对象包含MutablePropertySources对象, 里面包含一个类型为PropertySource的list,配置的优先级是通过这个list的位置决定的。 configureEnvironment方法会判断defaultProperties属性是否存在,有的话会设置为应用默认配置(优先级最低);然后检查run方法传入的args是否存在,
如果存在会设置为commandLineArgs作为优先级最高的配置,最后会设置应用的active profiles。
environment准备好之后会发布ApplicationEnvironmentPreparedEvent事件,这个事件发布之后主要来关注两个ApplicationListener
1.BootstrapApplicationListener
BootstrapApplicationListener会根据
String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
这个配置默认加载bootstrap配置文件,通过工厂加载机制加载key为org.springframework.cloud.bootstrap.BootstrapConfiguration的配置类作为sources启动一个初始化SpringApplication。 这些sources里面关注这个类
public class PropertySourceBootstrapConfiguration implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered
这是一个初始化器,通过ApplicationEnvironmentPreparedEvent传过来的主应用SpringApplication的addInitializers方法加入了这个初始化器,这个初始化器通过List
2.ConfigFileApplicationListener
这个监听器的优先级比上一个低,这个类也是一个EnvironmentPostProcessor的实现类,EnvironmentPostProcessor是spring boot对environment的一个扩展组件,可以对当前environment做出变更,内部通过PropertySourceLoader加载4个位置的配置文件,默认识别4种目录优先级依次为: file:./config/[当前目录下的config目录]
file:./[当前目录]
classpath:/config/[类加载目录下的config目录]
classpath:/[类加载目录]
应用端的配置加载说道这里,接下来说说config server的扩展。 对于spring cloud config server端,增加了对公共配置的支持,spring cloud config server端使用如下接口获取environment
public interface EnvironmentRepository {
Environment findOne(String var1, String var2, String var3);
}
支持三种方式获取配置git、svn、vault,默认git方式,默认最终实现类为SearchPathCompositeEnvironmentRepository,这个类会组合配置的EnvironmentRepository实现,获取配置内容。扩展获取公共配置库功能通过扩展该类,定义了公共配置库配置项config.public.projects,读取该配置的内容,从该配置项的配置仓库拉取配置:
public class CommonSearchPathCompositeEnvironmentRepository extends SearchPathCompositeEnvironmentRepository {
private Logger logger = LoggerFactory.getLogger(CommonSearchPathCompositeEnvironmentRepository.class);
public CommonSearchPathCompositeEnvironmentRepository(List<EnvironmentRepository> environmentRepositories) {
super(environmentRepositories);
}
private static final String PUBLIC_CONFIG_PROJECTS = "config.public.projects";
@Override
public Environment findOne(String application, String profile, String label) {
Environment environment = super.findOne(application,profile,label);
String[] publicProjects = publicProjects(environment.getPropertySources());
if (publicProjects != null){
for(String publicProject : publicProjects){
try{
Environment publicEnvironment = super.findOne(publicProject,profile,label);
environment.addAll(publicEnvironment.getPropertySources());
} catch (Exception e){
logger.error("get public config fail,e:{}",e.getMessage());
}
}
}
return environment;
}
private String[] publicProjects(List<PropertySource> propertySources){
for (PropertySource propertySource:propertySources){
if (propertySource.getSource().containsKey(PUBLIC_CONFIG_PROJECTS)) {
return propertySource.getSource().get(PUBLIC_CONFIG_PROJECTS).toString().split(",");
}
}
return null;
}
}
通过import自定义的配置类exclude原有的配置类替换config server的配置类:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ExtendConfigServerConfiguration.class})
public @interface EnableCustomConfigServer {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication(exclude = {ConfigServerAutoConfiguration.class})
@EnableDiscoveryClient
@EnableCustomConfigServer
public @interface SpringCloudConfigApplication {
}
spring cloud config的分布式配置更新依赖于spring cloud bus,通过请求/bus/refresh endpoint,应用会从spring cloud bus消息总线发送RefreshRemoteApplicationEvent,通过定义destinationService可以定义刷新的目标应用,应用刷新完毕会ack一个AckRemoteApplicationEvent,收集该消息可以知道什么应用的几个实例刷新完毕。
先说到这里吧,配置的web管理界面:
http://spring-config-center.nidianwo.com/#/dashboard/app wiki地址:
http://wiki.nidianwo.com/pages/viewpage.action?pageId=13249588
欢迎多多使用~