网站首页 编程语言 正文
文章目录
- 前言
- 一、Spring Cloud Config Service
- 引入POM文件
- 启动配置服务
- 基于(Native)本地配置
- 配置类NativeEnvironmentProperties
- 解析本地配置文件 NativeEnvironmentRepository
- 配置文件 application.yml
- 基于Git配置
- 配置类 JGitEnvironmentProperties
- 配置类的抽象类
- 解析Git存库配置类MultipleJGitEnvironmentRepository
- 配置文件 application.yml
- 基于JDBC配置
- 基于JDBC存储配置类JdbcEnvironmentProperties
- 解析JDBC配置类
- 配置文件application.yml
- 二、Spring Cloud Config Client
- 引入POM文件
- 配置文件bootstrap.yml
前言
通过统一配置服务,可以解决服务中配置文件分散,不利于管理。
一、Spring Cloud Config Service
引入POM文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
启动配置服务
@SpringBootApplication
//服务发现客户端
@EnableDiscoveryClient
//配置服务器端
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args){
SpringApplication.run(ConfigApplication.class,args);
}
}
基于(Native)本地配置
配置类NativeEnvironmentProperties
@ConfigurationProperties("spring.cloud.config.server.native")
public class NativeEnvironmentProperties implements EnvironmentRepositoryProperties {
/**
* 确定解密期间如何处理异常的标志(默认为false)
*/
private Boolean failOnError = false;
/**
* 用于确定是否应添加标签位置的标志
*/
private Boolean addLabelLocations = true;
/**
* 默认标签
*/
private String defaultLabel = "master";
/**
* 搜索配置文件路径,文件格式类似Spring Boot的配置文件.
* 本地文件配置如: [classpath:/,classpath:/config/,file:./,file:./config/].
*/
private String[] searchLocations = new String[0];
/**
* 本地仓库版本号
*/
private String version;
private int order = Ordered.LOWEST_PRECEDENCE;
解析本地配置文件 NativeEnvironmentRepository
重要代码如下
@Override
public Environment findOne(String config, String profile, String label,
boolean includeOrigin) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(
PropertyPlaceholderAutoConfiguration.class);
ConfigurableEnvironment environment = getEnvironment(profile);
builder.environment(environment);
builder.web(WebApplicationType.NONE).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()));
try (ConfigurableApplicationContext context = builder.run(args)) {
environment.getPropertySources().remove("profiles");
return clean(new PassthruEnvironmentRepository(environment).findOne(config,
profile, label, includeOrigin));
}
catch (Exception e) {
String msg = String.format(
"Could not construct context for config=%s profile=%s label=%s includeOrigin=%b",
config, profile, label, includeOrigin);
String completeMessage = NestedExceptionUtils.buildMessage(msg,
NestedExceptionUtils.getMostSpecificCause(e));
throw new FailedToConstructEnvironmentException(completeMessage, e);
}
}
@Override
public Locations getLocations(String application, String profile, String label) {
String[] locations = this.searchLocations;
if (this.searchLocations == null || this.searchLocations.length == 0) {
locations = DEFAULT_LOCATIONS;
}
Collection<String> output = new LinkedHashSet<String>();
if (label == null) {
label = this.defaultLabel;
}
for (String location : locations) {
String[] profiles = new String[] { profile };
if (profile != null) {
profiles = StringUtils.commaDelimitedListToStringArray(profile);
}
String[] apps = new String[] { application };
if (application != null) {
apps = StringUtils.commaDelimitedListToStringArray(application);
}
for (String prof : profiles) {
for (String app : apps) {
String value = location;
if (application != null) {
value = value.replace("{application}", app);
}
if (prof != null) {
value = value.replace("{profile}", prof);
}
if (label != null) {
value = value.replace("{label}", label);
}
if (!value.endsWith("/")) {
value = value + "/";
}
if (isDirectory(value)) {
output.add(value);
}
}
}
}
if (this.addLabelLocations) {
for (String location : locations) {
if (StringUtils.hasText(label)) {
String labelled = location + label.trim() + "/";
if (isDirectory(labelled)) {
output.add(labelled);
}
}
}
}
return new Locations(application, profile, label, this.version,
output.toArray(new String[0]));
}
private ConfigurableEnvironment getEnvironment(String profile) {
ConfigurableEnvironment environment = new StandardEnvironment();
Map<String, Object> map = new HashMap<>();
map.put("spring.profiles.active", profile);
map.put("spring.main.web-application-type", "none");
environment.getPropertySources().addFirst(new MapPropertySource("profiles", map));
return environment;
}
protected Environment clean(Environment value) {
Environment result = new Environment(value.getName(), value.getProfiles(),
value.getLabel(), this.version, value.getState());
for (PropertySource source : value.getPropertySources()) {
String name = source.getName();
if (this.environment.getPropertySources().contains(name)) {
continue;
}
name = name.replace("applicationConfig: [", "");
name = name.replace("]", "");
if (this.searchLocations != null) {
boolean matches = false;
String normal = name;
if (normal.startsWith("file:")) {
normal = StringUtils
.cleanPath(new File(normal.substring("file:".length()))
.getAbsolutePath());
}
String profile = result.getProfiles() == null ? null
: StringUtils.arrayToCommaDelimitedString(result.getProfiles());
for (String pattern : getLocations(result.getName(), profile,
result.getLabel()).getLocations()) {
if (!pattern.contains(":")) {
pattern = "file:" + pattern;
}
if (pattern.startsWith("file:")) {
pattern = StringUtils
.cleanPath(new File(pattern.substring("file:".length()))
.getAbsolutePath())
+ "/";
}
if (logger.isTraceEnabled()) {
logger.trace("Testing pattern: " + pattern
+ " with property source: " + name);
}
if (normal.startsWith(pattern)
&& !normal.substring(pattern.length()).contains("/")) {
matches = true;
break;
}
}
if (!matches) {
// Don't include this one: it wasn't matched by our search locations
if (logger.isDebugEnabled()) {
logger.debug("Not adding property source: " + name);
}
continue;
}
}
logger.info("Adding property source: " + name);
result.add(new PropertySource(name, source.getSource()));
}
return result;
}
private String[] getArgs(String application, String profile, String label) {
List<String> list = new ArrayList<String>();
String config = application;
if (!config.startsWith("application")) {
config = "application," + config;
}
list.add("--spring.config.name=" + config);
list.add("--spring.cloud.bootstrap.enabled=false");
list.add("--encrypt.failOnError=" + this.failOnError);
list.add("--spring.config.location=" + StringUtils.arrayToCommaDelimitedString(
getLocations(application, profile, label).getLocations()));
return list.toArray(new String[0]);
}
配置文件 application.yml
spring:
application:
name: config
profiles:
active: native
cloud:
config:
server:
native:
search-locations: classpath:/config/
# 默认标签 master
default-label: master
version: 1.0
# 默认值 {spring.application.name}
name: config
基于Git配置
配置类 JGitEnvironmentProperties
public class JGitEnvironmentProperties extends AbstractScmAccessorProperties
implements HttpEnvironmentRepositoryProperties {
private static final String DEFAULT_LABEL = "master";
/**
* 启动时是否克隆库(按需克隆).
* 会导致第一次启动较慢,但是第一次查询较快.
*/
private boolean cloneOnStart = false;
/** 是否克隆存储库的子模块 */
private boolean cloneSubmodules = false;
/**
* 指示存储库应强制拉的标志。如果为true,则丢弃任何本地
* 更改和从远程存储库获取
*/
private boolean forcePull;
/** 连接Git超时时间,默认5秒 */
private int timeout = 5;
/** 指示如果分支的来源被跟踪,则应在本地删除该分支 */
private boolean deleteUntrackedBranches = false;
/** 连接Git时,如果是HTTPS是否跳过SSL验证 */
private boolean skipSslValidation = false;
/** 刷新Git存储库,每次间隔的时间(秒) */
private int refreshRate = 0;
/**
* 有效的SSH私钥。如果IgnoreLocalSShsSettings为true且Git URI为,则必须设置
* SSH 格式.
*/
private String privateKey;
/**
* 算法如下一种: ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384,ecdsa-sha2-nistp521.
* 如果设置了hostKey,则必须要设置.
*/
private String hostKeyAlgorithm;
/** 有效的SSH主机密钥。如果还设置了hostKeyAlgorithm,则必须设置 */
private String hostKey;
/** 本地已知主机文件 */
private String knownHostsFile;
/**
* 首先身份认证
* 重写服务器身份验证方法顺序。
* 如果服务器在公钥方法之前具有键盘交互身份验证,那么这应该可以避免登录提示
*/
@Pattern(regexp = "([\\w -]+,)*([\\w -]+)")
private String preferredAuthentications;
/** 如果为true,请使用基于属性的SSH配置,而不是基于文件的SSH配置。 */
private boolean ignoreLocalSshSettings;
/** 如果为false,则忽略主机密钥的错误。 */
private boolean strictHostKeyChecking = true;
/** HTTP 代理配置. */
private Map<ProxyHostProperties.ProxyForScheme, ProxyHostProperties> proxy = new HashMap<>();
配置类的抽象类
public class AbstractScmAccessorProperties implements EnvironmentRepositoryProperties {
static final String[] DEFAULT_LOCATIONS = new String[] { "/" };
/** 远程仓库URI. */
private String uri;
/** 存储库本地工作副本的基本目录. */
private File basedir;
/** 搜索要在本地工作副本中使用的路径。默认情况下,只搜索根 */
private String[] searchPaths = DEFAULT_LOCATIONS.clone();
/** 远程仓库认知用户名. */
private String username;
/** 远程仓库认证密码. */
private String password;
/** 解锁SSH私钥的口令. */
private String passphrase;
/** 拒绝来自不在已知主机列表中的远程服务器的传入SSH主机密钥 */
private boolean strictHostKeyChecking = true;
/** 环境存储库的顺序. */
private int order = Ordered.LOWEST_PRECEDENCE;
/** 与远程存储库一起使用的默认标签 */
private String defaultLabel;
解析Git存库配置类MultipleJGitEnvironmentRepository
重要代码
@Override
public Locations getLocations(String application, String profile, String label) {
for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {
if (repository.matches(application, profile, label)) {
for (JGitEnvironmentRepository candidate : getRepositories(repository,
application, profile, label)) {
try {
Environment source = candidate.findOne(application, profile,
label, false);
if (source != null) {
return candidate.getLocations(application, profile, label);
}
}
catch (Exception e) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Cannot retrieve resource locations from "
+ candidate.getUri() + ", cause: ("
+ e.getClass().getSimpleName() + ") "
+ e.getMessage(), e);
}
continue;
}
}
}
}
JGitEnvironmentRepository candidate = getRepository(this, application, profile,
label);
if (candidate == this) {
return super.getLocations(application, profile, label);
}
return candidate.getLocations(application, profile, label);
}
@Override
public Environment findOne(String application, String profile, String label,
boolean includeOrigin) {
for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {
if (repository.matches(application, profile, label)) {
for (JGitEnvironmentRepository candidate : getRepositories(repository,
application, profile, label)) {
try {
if (label == null) {
label = candidate.getDefaultLabel();
}
Environment source = candidate.findOne(application, profile,
label, includeOrigin);
if (source != null) {
return source;
}
}
catch (Exception e) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(
"Cannot load configuration from " + candidate.getUri()
+ ", cause: (" + e.getClass().getSimpleName()
+ ") " + e.getMessage(),
e);
}
continue;
}
}
}
}
JGitEnvironmentRepository candidate = getRepository(this, application, profile,
label);
if (label == null) {
label = candidate.getDefaultLabel();
}
if (candidate == this) {
return super.findOne(application, profile, label, includeOrigin);
}
return candidate.findOne(application, profile, label, includeOrigin);
}
private List<JGitEnvironmentRepository> getRepositories(
JGitEnvironmentRepository repository, String application, String profile,
String label) {
List<JGitEnvironmentRepository> list = new ArrayList<>();
String[] profiles = profile == null ? new String[] { null }
: StringUtils.commaDelimitedListToStringArray(profile);
for (int i = profiles.length; i-- > 0;) {
list.add(getRepository(repository, application, profiles[i], label));
}
return list;
}
JGitEnvironmentRepository getRepository(JGitEnvironmentRepository repository,
String application, String profile, String label) {
if (!repository.getUri().contains("{")) {
return repository;
}
String key = repository.getUri();
// cover the case where label is in the uri, but no label was sent with the
// request
if (key.contains("{label}") && label == null) {
label = repository.getDefaultLabel();
}
if (application != null) {
key = key.replace("{application}", application);
}
if (profile != null) {
key = key.replace("{profile}", profile);
}
if (label != null) {
key = key.replace("{label}", label);
}
if (!this.placeholders.containsKey(key)) {
this.placeholders.put(key, getRepository(repository, key));
}
return this.placeholders.get(key);
}
private JGitEnvironmentRepository getRepository(JGitEnvironmentRepository source,
String uri) {
JGitEnvironmentRepository repository = new JGitEnvironmentRepository(null,
new JGitEnvironmentProperties());
File basedir = repository.getBasedir();
BeanUtils.copyProperties(source, repository);
repository.setUri(uri);
repository.setBasedir(new File(source.getBasedir(), basedir.getName()));
return repository;
}
配置文件 application.yml
cloud:
config:
server:
git:
uri: git@gitee.com:swg/config.git
private-key: xxx
host-key-algorithm: ecdsa-sha2-nistp256
known-hosts-file: ~/.ssh/known_hosts
search-paths: cloud
label: master
基于JDBC配置
基于JDBC存储配置类JdbcEnvironmentProperties
@ConfigurationProperties("spring.cloud.config.server.jdbc")
public class JdbcEnvironmentProperties implements EnvironmentRepositoryProperties {
//默认查询配置语句
private static final String DEFAULT_SQL = "SELECT KEY, VALUE from PROPERTIES"
+ " where APPLICATION=? and PROFILE=? and LABEL=?";
/**
* 是否启动JDBC配置
*/
private boolean enabled = true;
private int order = Ordered.LOWEST_PRECEDENCE - 10;
/** 查询数据库中key和value的SQL */
private String sql = DEFAULT_SQL;
/**
* 查询失败报异常
*/
private boolean failOnError = true;
解析JDBC配置类
重要代码:在这里会将 key 和value的Result 转为 map
会有一个默认的共有配置: application: application, profile: default
@Override
public Environment findOne(String application, String profile, String label) {
String config = application;
if (StringUtils.isEmpty(label)) {
label = "master";
}
if (StringUtils.isEmpty(profile)) {
profile = "default";
}
if (!profile.startsWith("default")) {
profile = "default," + profile;
}
String[] profiles = StringUtils.commaDelimitedListToStringArray(profile);
Environment environment = new Environment(application, profiles, label, null,
null);
if (!config.startsWith("application")) {
config = "application," + config;
}
List<String> applications = new ArrayList<String>(new LinkedHashSet<>(
Arrays.asList(StringUtils.commaDelimitedListToStringArray(config))));
List<String> envs = new ArrayList<String>(
new LinkedHashSet<>(Arrays.asList(profiles)));
Collections.reverse(applications);
Collections.reverse(envs);
for (String app : applications) {
for (String env : envs) {
try {
Map<String, String> next = (Map<String, String>) this.jdbc.query(
this.sql, new Object[] { app, env, label }, this.extractor);
if (!next.isEmpty()) {
environment.add(new PropertySource(app + "-" + env, next));
}
}
catch (DataAccessException e) {
if (!failOnError) {
if (logger.isDebugEnabled()) {
logger.debug(
"Failed to retrieve configuration from JDBC Repository",
e);
}
}
else {
throw e;
}
}
}
}
return environment;
}
配置文件application.yml
spring:
application:
name: config
profiles:
active: native
cloud:
config:
server:
jdbc:
# 其中key和value 是可以随意字段只要含义相同即可
sql: SELECT KEY, VALUE from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?
二、Spring Cloud Config Client
引入POM文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
配置文件bootstrap.yml
spring:
application:
name: config
cloud:
config:
#
label: master
uri: http://localhost:9100
# 默认名称 ${spring.application.name}
name: custmoer
profile: dev
原文链接:https://blog.csdn.net/swg321321/article/details/125982360
相关推荐
- 2022-06-06 python 包之 threading 多线程_python
- 2021-12-03 C++中signed main和int main的区别_C 语言
- 2022-04-09 Nginx 提示10013: An attempt was made to access a soc
- 2022-08-05 C++深入探究哈希表如何封装出unordered_set和unordered_map_C 语言
- 2022-07-16 SpringMVC基础工作原理以及实例
- 2022-09-03 docker镜像管理命令详解_docker
- 2022-12-30 Android入门之在子线程中调用Handler详解_Android
- 2022-03-07 C语言switch语句详解_C 语言
- 最近更新
-
- window11 系统安装 yarn
- 超详细win安装深度学习环境2025年最新版(
- Linux 中运行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存储小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基础操作-- 运算符,流程控制 Flo
- 1. Int 和Integer 的区别,Jav
- spring @retryable不生效的一种
- Spring Security之认证信息的处理
- Spring Security之认证过滤器
- Spring Security概述快速入门
- Spring Security之配置体系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置权
- redisson分布式锁中waittime的设
- maven:解决release错误:Artif
- restTemplate使用总结
- Spring Security之安全异常处理
- MybatisPlus优雅实现加密?
- Spring ioc容器与Bean的生命周期。
- 【探索SpringCloud】服务发现-Nac
- Spring Security之基于HttpR
- Redis 底层数据结构-简单动态字符串(SD
- arthas操作spring被代理目标对象命令
- Spring中的单例模式应用详解
- 聊聊消息队列,发送消息的4种方式
- bootspring第三方资源配置管理
- GIT同步修改后的远程分支