日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Spring Cloud Config配置服務

作者:swg321321 更新時間: 2022-08-19 編程語言

文章目錄

  • 前言
  • 一、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

欄目分類
最近更新