配置中心用来集中管理应用不同环境(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
欢迎多多使用~