org.springframework.cloud.config是Spring Cloud处理配置管理的一种解决方案。它含服务端和客户端2部分。服务端以接口形式提供服务的配置信息,配置信息支持以本地文件形式或远程Git方式;客户端通过接口获取配置,并初始化自身服务。
Server端
- 创建Maven项目,步骤略
- 在pom.xml添加相关依赖
<!-- 注册到eureka -->
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
<!-- config server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
- 在主函数类添加@EnableConfigServer
@SpringBootApplication @EnableConfigServer public class ConfigApplication { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); } }
4)在boostrap.yml添加config和eureka配置
spring: application: name: config profiles: active: native cloud: config: server: native: search-locations: classpath:/config/dev # git形式 # cloud: # config: # server: # git: # uri: https://xxx.com/xxx/properties.git # username: **** # password: **** eureka: instance: lease-renewal-interval-in-seconds: 10 lease-expiration-duration-in-seconds: 20 prefer-ip-address: false client: security: basic: user: admin password: 666666 serviceUrl: defaultZone: http://${eureka.client.security.basic.user}:${eureka.client.security.basic.password}@localhost:8761/eureka/
- 本项目采用本地文件配置,指定的路径为search-locations: classpath:/config/dev,在resource目录下新建config目录,然后在config目录下新建dev目录(dev:开发环境,test:测试环境,prod:生产环境),这个目录下之后根据项目名称新建对应的配置文件,也可以将统一的配置写在application.yml里面放在dev目录内。
如application.yml配置文件
feign: compression: request: enabled: true mime-types: text/xml,application/xml,application/json,application/zip min-request-size: 2048 response: enabled: true # 配置响应GZIP压缩 hystrix: enabled: true httpclient: enabled: false okhttp: enabled: true hystrix: command: default: execution: timeout: isolation: thread: timeoutInMilliseconds: 20000 threadpool: default: coreSize: 20 maximumSize: 50 maxQueueSize: -1 allowMaximumSizeToDivergeFromCoreSize: true ribbon: ConnectTimeout: 20000 ReadTimeout: 20000 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 0
如gateway.yml配置
server: port: 80 # 默认开放端口 80 spring: cloud: gateway: discovery: locator: enabled: true # 开启服务发现路由规则 lowerCaseServiceId: true # 开启小写serviceId
Client端
- 新建Maven项目,步骤略。在pom.xml添加config依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
在pom.xml添加config和eureka配置
spring: application: name: gateway # 当前服务名称 cloud: config: discovery: enabled: true # 开启通过服务名称访问config-server service-id: config # config-server服务名称 eureka: instance: lease-renewal-interval-in-seconds: 1 # 表示eureka间隔多久去拉取服务注册信息,默认为30秒,对于gateway,如果要迅速获取服务注册状态,可以缩小该值,比如1秒 lease-expiration-duration-in-seconds: 2 # 表示eureka至上一次收到心跳之后,等待下一次心跳的超时时间,在这个时间内没收到下一次心跳,则将移除该instance prefer-ip-address: false client: security: basic: user: admin# eureka服务账号 password: 666666 # eureka服务密码 serviceUrl: defaultZone: http://${eureka.client.security.basic.user}:${eureka.client.security.basic.password}@localhost:8761/eureka/
/** 小白解读时间,若有不妥之处,望请不吝赐教 **/
config源码结构
EnableConfigServer类
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(ConfigServerConfiguration.class) public @interface EnableConfigServer { }
ConfigServerConfiguration类
@Configuration public class ConfigServerConfiguration { class Marker {} @Bean public Marker enableConfigServerMarker() { return new Marker(); } }
ConfigServerAutoConfiguration类
@Configuration @ConditionalOnBean(ConfigServerConfiguration.Marker.class) @EnableConfigurationProperties(ConfigServerProperties.class) @Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class, ResourceRepositoryConfiguration.class, ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class }) public class ConfigServerAutoConfiguration { }
ConfigServerProperties类
@ConfigurationProperties("spring.cloud.config.server") public class ConfigServerProperties {
……
}
EnvironmentRepositoryConfiguration是加载配置方式,默认配置仓读取方式是git,此外还支持native、jdbc、svn等方式,
@Configuration @EnableConfigurationProperties({ SvnKitEnvironmentProperties.class, CredhubEnvironmentProperties.class, JdbcEnvironmentProperties.class, NativeEnvironmentProperties.class, VaultEnvironmentProperties.class }) @Import({ CompositeRepositoryConfiguration.class, JdbcRepositoryConfiguration.class, VaultRepositoryConfiguration.class, CredhubConfiguration.class, CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class, NativeRepositoryConfiguration.class, GitRepositoryConfiguration.class, DefaultRepositoryConfiguration.class }) public class EnvironmentRepositoryConfiguration {
……
@Configuration @ConditionalOnMissingBean(EnvironmentRepository.class) @Profile("native") class NativeRepositoryConfiguration { @Bean public NativeEnvironmentRepository nativeEnvironmentRepository(NativeEnvironmentRepositoryFactory factory, NativeEnvironmentProperties environmentProperties) { return factory.build(environmentProperties); } } @Configuration @Profile("git") class GitRepositoryConfiguration extends DefaultRepositoryConfiguration { } @Configuration @Profile("subversion") class SvnRepositoryConfiguration { @Bean public SvnKitEnvironmentRepository svnKitEnvironmentRepository(SvnKitEnvironmentProperties environmentProperties, SvnEnvironmentRepositoryFactory factory) { return factory.build(environmentProperties); } } @Configuration @Profile("vault") class VaultRepositoryConfiguration { @Bean public VaultEnvironmentRepository vaultEnvironmentRepository(VaultEnvironmentRepositoryFactory factory, VaultEnvironmentProperties environmentProperties) throws Exception { return factory.build(environmentProperties); } } @Configuration @Profile("credhub") class CredhubRepositoryConfiguration { @Bean public CredhubEnvironmentRepository credhubEnvironmentRepository(CredhubEnvironmentRepositoryFactory factory, CredhubEnvironmentProperties environmentProperties) { return factory.build(environmentProperties); } } @Configuration @Profile("jdbc") @ConditionalOnClass(JdbcTemplate.class) class JdbcRepositoryConfiguration { @Bean @ConditionalOnBean(JdbcTemplate.class) public JdbcEnvironmentRepository jdbcEnvironmentRepository(JdbcEnvironmentRepositoryFactory factory, JdbcEnvironmentProperties environmentProperties) { return factory.build(environmentProperties); } }
……
}
客户端连接实现,
@Configuration @EnableConfigurationProperties public class ConfigServiceBootstrapConfiguration {
……
@Bean @ConditionalOnMissingBean(ConfigServicePropertySourceLocator.class) @ConditionalOnProperty(value = "spring.cloud.config.enabled", matchIfMissing = true) public ConfigServicePropertySourceLocator configServicePropertySource(ConfigClientProperties properties) { ConfigServicePropertySourceLocator locator = new ConfigServicePropertySourceLocator( properties); return locator;
…… }
然后进入DiscoveryClientConfigServiceBootstrapConfiguration执行onApplicationEvent()方法
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false) @Configuration @Import({ UtilAutoConfiguration.class }) @EnableDiscoveryClient public class DiscoveryClientConfigServiceBootstrapConfiguration implements SmartApplicationListener {
……
}
当客户端请求服务端,接口定义在EnvironmentController,接口命名labelled。
@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(!acceptEmpty && (environment == null || environment.getPropertySources().isEmpty())){ throw new EnvironmentNotFoundException("Profile Not found"); } return environment; }
……
}
labelled调用NativeEnvironmentRepository的方法findOne方法,加载配置返回给客户端。