spring cloud configは配置ファイルの原理を引き出します.


ずっとspring cloud configに対してどのようにgitから配置ファイルにロードするかに興味があります.
spring cloud configの教程とdemoは直接springの公式サイトから勉強できます.https://spring.io/projects/spring-cloud-config
公式文書
私は主にこの二つの文書を見ます.
  • https://cloud.spring.io/spring-cloud-config/reference/html/
  • https://spring.io/guides/gs/centralized-configuration/
  • まず公式教程の中でspring cloud configの構成を整えて、config clientの端で配置更新を行うなら、actuatに対する依存を加える必要があります.
    
        org.springframework.boot
        spring-boot-starter-actuator
    
    refreshのendpointを開いて、すべてを開くなら、managementの配置を*と書けばいいです.
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    ソースの探究
    短く言ってください
    spring cloud config clientにプロファイルをロードすることは、config serverのhttpインターフェースにアクセスすることによって実現される.
    出力されたログで見ることができます.そのcontrollerのrequest Mappingアドレスは以下の通りです.
    /{application}/{profile}[/{label}]
    config server拉が配置ファイルを取る原理を研究するために、このRequest Mappingのコードを研究すればいいです.
    @EnbaleConfigServer注で見つけました.ConfigServer Configrations.class->Marker->Evironment RepositoryConfigration->
    GitRepositoryConfiguration->DefaultRepositoryConfiguration->MultipleJGitEnvironmentRepository->org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository#findOne->org.springframework.cloud.config.server.environment.EnvironmentController
    最後のEvironment Controllerはconfig serverから提供されたcontrollerです.上記のrequest Mappingアドレスはこのcontollerの中にあります.
    	@RequestMapping("/{name}/{profiles:.*[^-].*}")
    	public Environment defaultLabel(@PathVariable String name,
    			@PathVariable String profiles) {
    		return labelled(name, profiles, null);
    	}
    その最終的にはlabelled方法を実行します.
    	@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 (!this.acceptEmpty
    				&& (environment == null || environment.getPropertySources().isEmpty())) {
    			throw new EnvironmentNotFoundException("Profile Not found");
    		}
    		return environment;
    	}
    そして、this.repository.findOneメソッドを実行します.gitで作成した環境設定ファイルなら、org.springframbork.cloud.com fig.server.environment.MultippleJGivronment Repository:.
    	@Override
    	public Environment findOne(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 {
    						if (label == null) {
    							label = candidate.getDefaultLabel();
    						}
    						Environment source = candidate.findOne(application, profile,
    								label);
    						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);
    		}
    		return candidate.findOne(application, profile, label);
    	}
    findOneメソッドの3つのパラメータは、それぞれappicationの名前、profileの名前とコード分岐の名前を表します.
    従ってorg.springframe ework.cloud.co.nfig.server.environment.AbstractSmEnvironment Repository方法に入る:
    	@Override
    	public synchronized Environment findOne(String application, String profile,
    			String label) {
    		NativeEnvironmentRepository delegate = new NativeEnvironmentRepository(
    				getEnvironment(), new NativeEnvironmentProperties());
    		Locations locations = getLocations(application, profile, label);
    		delegate.setSearchLocations(locations.getLocations());
    		Environment result = delegate.findOne(application, profile, "");
    		result.setVersion(locations.getVersion());
    		result.setLabel(label);
    		return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(),
    				getUri());
    	}
    その中のLocations locations=get Locations(appication、profile、label)org.springframe ework.cloud.com nfig.server.environment.Multiple JGitEngment Repositoryを実行します.その後org.springframe.clodc.figs.server.environ.JGront.JGuint方法を実行します.
    	@Override
    	public synchronized Locations getLocations(String application, String profile,
    			String label) {
    		if (label == null) {
    			label = this.defaultLabel;
    		}
    		String version = refresh(label);
    		return new Locations(application, profile, label, version,
    				getSearchLocations(getWorkingDirectory(), application, profile, label));
    	}
    主要コード:
    ここを見たらrefreshに入ると大体分かります.
    /**
    	 * Get the working directory ready.
    	 * @param label label to refresh
    	 * @return head id
    	 */
    	public String refresh(String label) {
    		Git git = null;
    		try {
    			git = createGitClient();
    			if (shouldPull(git)) {
    				FetchResult fetchStatus = fetch(git, label);
    				if (this.deleteUntrackedBranches && fetchStatus != null) {
    					deleteUntrackedLocalBranches(fetchStatus.getTrackingRefUpdates(),
    							git);
    				}
    				// checkout after fetch so we can get any new branches, tags, ect.
    				checkout(git, label);
    				tryMerge(git, label);
    			}
    			else {
    				// nothing to update so just checkout and merge.
    				// Merge because remote branch could have been updated before
    				checkout(git, label);
    				tryMerge(git, label);
    			}
    			// always return what is currently HEAD as the version
    			return git.getRepository().findRef("HEAD").getObjectId().getName();
    		}
    		catch (RefNotFoundException e) {
    			throw new NoSuchLabelException("No such label: " + label, e);
    		}
    		catch (NoRemoteRepositoryException e) {
    			throw new NoSuchRepositoryException("No such repository: " + getUri(), e);
    		}
    		catch (GitAPIException e) {
    			throw new NoSuchRepositoryException(
    					"Cannot clone or checkout repository: " + getUri(), e);
    		}
    		catch (Exception e) {
    			throw new IllegalStateException("Cannot load environment", e);
    		}
    		finally {
    			try {
    				if (git != null) {
    					git.close();
    				}
    			}
    			catch (Exception e) {
    				this.logger.warn("Could not close git repository", e);
    			}
    		}
    	}
    上のコードの中で先に1つのgitクライアントを獲得して、そのgitクライアントの関連している依存はconfig serverのpom依存の中で探し当てることができます:
    
       org.eclipse.jgit
       org.eclipse.jgit
    
    gitクライアントを取得するとShuldPullの判断方法が実行されます.リモートのgitライブラリに入る必要があるかどうかを判断します.
    	protected boolean shouldPull(Git git) throws GitAPIException {
    		boolean shouldPull;
    
    		if (this.refreshRate > 0 && System.currentTimeMillis()
    				- this.lastRefresh < (this.refreshRate * 1000)) {
    			return false;
    		}
    
    		Status gitStatus = git.status().call();
    		boolean isWorkingTreeClean = gitStatus.isClean();
    		String originUrl = git.getRepository().getConfig().getString("remote", "origin",
    				"url");
    
    		if (this.forcePull && !isWorkingTreeClean) {
    			shouldPull = true;
    			logDirty(gitStatus);
    		}
    		else {
    			shouldPull = isWorkingTreeClean && originUrl != null;
    		}
    		if (!isWorkingTreeClean && !this.forcePull) {
    			this.logger.info("Cannot pull from remote " + originUrl
    					+ ", the working tree is not clean.");
    		}
    		return shouldPull;
    	}
    コードから分かるように、最初にrefreshRateを取得してリフレッシュ期間内にあるかどうかを判断します.このrefreshRateつまりconfig serverが提供してくれて、私たちが配置できるようにします.デフォルトではrefshRateの値は0です.
    その後、git statusコマンドを実行します.リモート倉庫が更新されているかどうかを判断します.
    更新が必要な場合は、fetchコマンド、checkoutコマンドを実行し、リモート倉庫のコードをマージするようにmergeコマンドを実行してみて、一連の解析操作を行います.
    後の具体的な解析処理操作については時間の関係でここでは深く研究していません.後で問題が発生した時に調べます.
    まとめ:
    今回のソースコードを通じて、config serverはリモート倉庫の神秘的なベールをどうやってロードするかを突き止めました.config serverも思ったほど神秘的ではありませんでした.
    また、Javaにはjgitというクライアントがあり、gitを操作できるということが分かりました.
    頑張って!よく勉強して毎日向上します.