一、ConfigServer如何提供配置
SpringCloud中申明ConfigServer时,通过@EnableConfigServer开启ConfigServer配置。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(ConfigServerConfiguration.class) public @interface EnableConfigServer { }
而EnableConfigServer中又引入了ConfigServerConfiguration,申明了内部类Maker,并装配为一个Bean。
@Configuration public class ConfigServerConfiguration { class Marker {} @Bean public Marker enableConfigServerMarker() { return new Marker(); } }
通过ConfigServerConfiguration.Maker又开启了ConfigServerAutoConfiguration配置(通过@ConditionalOnBean(ConfigServerConfiguration.Marker.class)
开启,在装配Maker时会执行该配置)。
@Configuration @ConditionalOnBean(ConfigServerConfiguration.Marker.class) @EnableConfigurationProperties(ConfigServerProperties.class) @Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class, ResourceRepositoryConfiguration.class, ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class, TransportConfiguration.class }) public class ConfigServerAutoConfiguration { }
通过@Import引入了6个重要的配置类
EnvironmentRepositoryConfiguration
:环境仓库配置,是关键的配置类
CompositeConfiguration
:混合配置,用于多环境下配置资源的加载
ResourceRepositoryConfiguration
:资源仓库相关配置
ConfigServerEncryptionConfiguration
:ConfigServer加密相关配置
ConfigServerMvcConfiguration
:对外暴露的MVC相关配置
TransportConfiguration
:运行transport命令前,配置回调
EnvironmentRepositoryConfiguration的配置
环境仓库的配置又细分为JDBC
、Vault
、svn
、Native(本地)
、Git
等配置,默认是Git配置.
多种配置方式,最终都会被装配成EnvironmentRepository,以本地配置装配为例看下类图结构:
EnvironmentRepository
1. NativeEnvironmentRepository本地配置加载
2. GitRepositoryConfiguration Git配置加载
等等...
二、ConfigClient的调用
ConfigServer在启动的时候会申明一个REST接口(EnvironmentController)当有配置客户端查询请求时,通过调用EnvironmentRepository.findOne方法返回一个Environment对象,客户端反序列化得到Environment对象。
@RequestMapping("/{name}/{profiles:.*[^-].*}") public Environment defaultLabel(@PathVariable String name, @PathVariable String profiles) { return labelled(name, profiles, null); } @RequestMapping("/{name}/{profiles}/{label:.*}") public Environment labelled(@PathVariable String name, @PathVariable String profiles, @PathVariable String label) { 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); return environment; }
findOne根据配置信息解析过滤配置属性,封装为Environment对象返回给客户端。
public class NativeEnvironmentRepository{ //在ConfigClient启动时调用 //config:文件名称,即在Configclient中配置的config.name //profile:ConfigClient中配置的config.profile @Override public Environment findOne(String config, String profile, String label) { //启动一个SpringBoot内部微型工程,用于加载配置文件 SpringApplicationBuilder builder = new SpringApplicationBuilder( PropertyPlaceholderAutoConfiguration.class); ConfigurableEnvironment environment = getEnvironment(profile); builder.environment(environment); builder.web(false).bannerMode(Mode.OFF); if (!logger.isDebugEnabled()) { // Make the mini-application startup less verbose builder.logStartupInfo(false); } String[] args = getArgs(config, profile, label); // Explicitly set the listeners (to exclude logging listener which would change // log levels in the caller) builder.application() .setListeners(Arrays.asList(new ConfigFileApplicationListener())); ConfigurableApplicationContext context = builder.run(args); environment.getPropertySources().remove("profiles"); try { //过滤出所有配置 return clean(new PassthruEnvironmentRepository(environment).findOne(config, profile, label)); } finally { context.close(); } } }
返回的Environment对象也可以直接通过在地址栏输入http连接看到
Environment