上一篇《 spring Cloud 微服务学习之ConfigServer》我们说了最基本的基于git服务器的config server,有一些朋友问我基于数据库的config server怎么弄,今天我们就讲解基于数据库的config server.
基于git(默认)的config server项目中我们在pom.xml导入:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
基于mysql数据库pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
基于数据库(mongodb)pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
基于数据库(H2)pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.191</version> </dependency>
其中H2和Mysql是差不多只是jdbc的配置不同,我们下面主要讲解怎么搭建基于mysql的config server
ConfigApplication.java
@EnableConfigServer @SpringBootApplication public class ConfigApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.web(true).sources(ConfigApplication.class); } }
我们先从Config Server源码来了解,spring cloud是怎么做的。
EnableConfigServer的源码
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Import({EnvironmentRepositoryConfiguration.class, ResourceRepositoryConfiguration.class, ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class}) public @interface EnableConfigServer { }
我们可以看见EnableConfigServer的注释中有一个导入的配置
@Import({EnvironmentRepositoryConfiguration.class, ResourceRepositoryConfiguration.class, ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class})
而配置资源的configuration是EnvironmentRepositoryConfiguration源码如下:
@Configuration @ConditionalOnMissingBean({EnvironmentRepository.class}) @EnableConfigurationProperties({ConfigServerProperties.class}) public class EnvironmentRepositoryConfiguration { public EnvironmentRepositoryConfiguration() { } @Bean @ConditionalOnProperty( value = {"spring.cloud.config.server.health.enabled"}, matchIfMissing = true ) public ConfigServerHealthIndicator configServerHealthIndicator(EnvironmentRepository repository) { return new ConfigServerHealthIndicator(repository); } @Configuration @Profile({"subversion"}) protected static class SvnRepositoryConfiguration { @Autowired private ConfigurableEnvironment environment; @Autowired private ConfigServerProperties server; protected SvnRepositoryConfiguration() { } @Bean public EnvironmentRepository environmentRepository() { SvnKitEnvironmentRepository repository = new SvnKitEnvironmentRepository(this.environment); if(this.server.getDefaultLabel() != null) { repository.setDefaultLabel(this.server.getDefaultLabel()); } return repository; } } @Configuration @ConditionalOnMissingBean({EnvironmentRepository.class}) protected static class GitRepositoryConfiguration { @Autowired private ConfigurableEnvironment environment; @Autowired private ConfigServerProperties server; protected GitRepositoryConfiguration() { } @Bean public EnvironmentRepository environmentRepository() { MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment); if(this.server.getDefaultLabel() != null) { repository.setDefaultLabel(this.server.getDefaultLabel()); } return repository; } } @Configuration @Profile({"native"}) protected static class NativeRepositoryConfiguration { @Autowired private ConfigurableEnvironment environment; protected NativeRepositoryConfiguration() { } @Bean public EnvironmentRepository environmentRepository() { return new NativeEnvironmentRepository(this.environment); } } }
可以通过:spring.profiles.active=xxx来激活相应的环境配置,其中
@Configuration @ConditionalOnMissingBean({EnvironmentRepository.class}) protected static class GitRepositoryConfiguration { @Autowired private ConfigurableEnvironment environment; @Autowired private ConfigServerProperties server; protected GitRepositoryConfiguration() { } @Bean public EnvironmentRepository environmentRepository() { MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(this.environment); if(this.server.getDefaultLabel() != null) { repository.setDefaultLabel(this.server.getDefaultLabel()); } return repository; } }
为当前默认配置资源服务
而我们需要做的就是将默认的GitRepositoryConfiguration替换为基于数据库的RepositoryConfiguration。
下面我们来创建自己的RepositoryConfiguration,暂时定为:DatabasesRepositoryConfiguration.
DatabasesRepositoryConfiguration.java
@Configuration @ConditionalOnMissingBean({EnvironmentRepository.class}) public class DatabasesRepositoryConfiguration { }
新建配置Entity:ConfigRepository.java用来存储应用名称、应用模块、应用环境(测试、生产)、应用版本来获取该程序的配置信息。
@Entity @Table public class ConfigRepository { @Id @GeneratedValue private Long configKey; private String application; //应用名称 private String profile; //应用模块 private String label; //应用环境 private String version; //应用版本 @ManyToMany @JoinTable(name = "config_properties_repository") private List<ConfigProperties> configPropertiesList = new ArrayList<>(); ... ... }
新建entity:ConfigProperties.java统一的配置信息,这里我为了达到配置重用的目的才创建ConfigProperties,这样我们只需要对ConfigRepository进行关联便可以得到灵活程序配置信息。
@Entity @Table public class ConfigProperties { @Id @GeneratedValue private Long propertiesKey; private String propertiesName; @Lob @Column @Type(type = "com.sixtykb.type.JsonType") private Map<String, String> content = new HashMap<>(); ... }
创建ConfigDbRepository.java,基于spring data jpa的查询dao。
@Repository public interface ConfigDbRepository extends JpaRepository<ConfigRepository, Long> { ConfigRepository findFirstByApplicationAndProfileAndLabel(String application, String profile, String label); }
创建config服务:ConfigRepositoryService.java,配置信息查询服务。
@Service public class ConfigRepositoryService { @Autowired private ConfigDbRepository configDbRepository; public ConfigRepository findByApplicationAndProfileAndLabel(String application, String profile, String label) { return configDbRepository.findFirstByApplicationAndProfileAndLabel(application, profile, label); } }
创建配置服务的核心服务:DatabasesEnvironmentRepository.java,生成该程序的配置对象。
public class DatabasesEnvironmentRepository implements EnvironmentRepository { @Autowired private ConfigRepositoryService configRepositoryService; @Override public Environment findOne(String application, String profile, String label) { if (StringUtils.isEmpty(application) || StringUtils.isEmpty(profile)) return null; ConfigRepository configRepositories = configRepositoryService.findByApplicationAndProfileAndLabel(application, profile, label); if (configRepositories != null) { Environment environment = new Environment(application, StringUtils.commaDelimitedListToStringArray(profile), label, configRepositories.getVersion()); for (ConfigProperties configProperties : configRepositories.getConfigPropertiesList()) { environment.add(new PropertySource(configProperties.getPropertiesName(), configProperties.getContent())); } return environment; } return new Environment(application, profile); } }
通过application、profile、label查询配置文件信息。
现在我们把DatabasesRepositoryConfiguration.java的代码补全:
@Configuration @ConditionalOnMissingBean(EnvironmentRepository.class) @ConditionalOnProperty("spring.cloud.config.server.databases") public class DatabasesRepositoryConfiguration { @Autowired private ConfigurableEnvironment environment; @Bean public SearchPathLocator searchPathLocator() { return new NativeEnvironmentRepository(environment); } @Bean @Primary public EnvironmentRepository openEnvironmentRepository() { return new DatabasesEnvironmentRepository(); } }
这里
@ConditionalOnProperty("spring.cloud.config.server.databases")
的意思是可以通过配置进行动态激活,也就是可以通过在bootstrap.properties配置文件中指定:
spring.cloud.config.server.databases=true
来激活基于数据库的config服务。
由于工作有些忙,很长时间没有写博客了,下次我们来讲解spring cloud 服务注册。
/**
* An {@link EnvironmentRepository} that picks up data from a relational database. The
* database should have a table called "PROPERTIES" with columns "APPLICATION", "PROFILE",
* "LABEL" (with the usual {@link Environment} meaning), plus "KEY" and "VALUE" for the
* key and value pairs in {@link Properties} style. Property values behave in the same way
* as they would if they came from Spring Boot properties files named
* {application}-{profile}.properties, including all the encryption and
* decryption, which will be applied as post-processing steps (i.e. not in this repository
* directly).
*
* @author Dave Syer
*
*/
public class JdbcEnvironmentRepository