【发布时间】:2014-12-20 09:11:50
【问题描述】:
我一直在尝试掌握位于此处的 Spring Boot 配置服务器:https://github.com/spring-cloud/spring-cloud-config,在更彻底地阅读了文档之后,我能够解决我的大部分问题。但是,我确实必须为基于文件的 PropertySourceLocator 编写一个附加类
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.config.client;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;
/**
* @author Al Dispennette
*
*/
@ConfigurationProperties("spring.cloud.config")
public class ConfigServiceFilePropertySourceLocator implements PropertySourceLocator {
private Logger logger = LoggerFactory.getLogger(ConfigServiceFilePropertySourceLocator.class);
private String env = "default";
@Value("${spring.application.name:'application'}")
private String name;
private String label = name;
private String basedir = System.getProperty("user.home");
@Override
public PropertySource<?> locate() {
try {
return getPropertySource();
} catch (IOException e) {
logger.error("An error ocurred while loading the properties.",e);
}
return null;
}
/**
* @throws IOException
*/
private PropertySource getPropertySource() throws IOException {
Properties source = new Properties();
Path path = Paths.get(getUri());
if(Files.isDirectory(path)){
Iterator<Path> itr = Files.newDirectoryStream(path).iterator();
String fileName = null!=label||StringUtils.hasText(label)?label:name+".properties";
logger.info("Searching for {}",fileName);
while(itr.hasNext()){
Path tmpPath = itr.next();
if(tmpPath.getFileName().getName(0).toString().equals(fileName)){
logger.info("Found file: {}",fileName);
source.load(Files.newInputStream(tmpPath));
}
}
}
return new PropertiesPropertySource("configService",source);
}
public String getUri() {
StringBuilder bldr = new StringBuilder(basedir)
.append(File.separator)
.append(env)
.append(File.separator)
.append(name);
logger.info("loading properties directory: {}",bldr.toString());
return bldr.toString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEnv() {
return env;
}
public void setEnv(String env) {
this.env = env;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getBasedir() {
return basedir;
}
public void setBasedir(String basedir) {
this.basedir = basedir;
}
}
然后我将它添加到 ConfigServiceBootstrapConfiguration.java
@Bean
public PropertySourceLocator configServiceFilePropertySource(
ConfigurableEnvironment environment) {
ConfigServiceFilePropertySourceLocator locator = new ConfigServiceFilePropertySourceLocator();
String[] profiles = environment.getActiveProfiles();
if (profiles.length==0) {
profiles = environment.getDefaultProfiles();
}
locator.setEnv(StringUtils.arrayToCommaDelimitedString(profiles));
return locator;
}
最后这达到了我想要的效果。 现在我很想知道这是否是我应该做的,或者我是否仍然缺少某些东西,而这已经被处理了,我只是错过了。
*****编辑戴夫要求的信息******
如果我取出文件属性源加载器并使用
更新 bootstrap.ymluri: file://${user.home}/resources
示例应用程序在启动时抛出以下错误:
ConfigServiceBootstrapConfiguration : Could not locate PropertySource: Object of class [sun.net.www.protocol.file.FileURLConnection] must be an instance of class java.net.HttpURLConnection
这就是为什么我认为需要额外的课程。就测试用例而言,我相信您正在谈论 SpringApplicationEnvironmentRepositoryTests.java 并且我同意创建环境有效,但作为一个整体,当 uri 协议为“文件”时,应用程序似乎没有按预期运行。
******其他编辑*******
这就是我理解它的工作原理: 示例项目依赖于 spring-cloud-config-client 工件,因此具有对 spring-cloud-config-server 工件的传递依赖。 客户端工件中的 ConfigServiceBootstrapConfiguration.java 创建一个 ConfigServicePropertySourceLocator 类型的属性源定位器 bean。 配置客户端工件中的 ConfigServicePropertySourceLocator.java 有注解 @ConfigurationProperties("spring.cloud.config") 并且属性uri存在于该类中,因此在bootstrap.yml文件中设置了spring.cloud.config.uri。
我相信 quickstart.adoc 中的以下声明强化了这一点:
当它运行时,它将从 端口 8888 上的默认本地配置服务器(如果它正在运行)。修改 您可以更改配置服务器的位置的启动行为 使用
bootstrap.properties(如application.properties,但对于 应用程序上下文的引导阶段),例如---- spring.cloud.config.uri:http://myconfigserver.com
此时,JGitEnvironmentRepository bean 是如何被使用并寻找到 github 的连接的。 我假设由于 uri 是在 ConfigServicePropertySourceLocator 中设置的属性,因此任何有效的 uri 协议都可以用于指向某个位置。 这就是为什么我使用 'file://' 协议认为服务器会获取 NativeEnvironmentRepository。
所以在这一点上,我确定我要么缺少某些步骤,要么需要添加文件系统属性源定位器。
我希望这更清楚一点。
全栈:
java.lang.IllegalArgumentException: Object of class [sun.net.www.protocol.file.FileURLConnection] must be an instance of class java.net.HttpURLConnection
at org.springframework.util.Assert.isInstanceOf(Assert.java:339)
at org.springframework.util.Assert.isInstanceOf(Assert.java:319)
at org.springframework.http.client.SimpleClientHttpRequestFactory.openConnection(SimpleClientHttpRequestFactory.java:182)
at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:140)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:76)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:541)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:506)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:448)
at org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.locate(ConfigServicePropertySourceLocator.java:68)
at org.springframework.cloud.bootstrap.config.ConfigServiceBootstrapConfiguration.initialize(ConfigServiceBootstrapConfiguration.java:70)
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:572)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at sample.Application.main(Application.java:20)
【问题讨论】:
-
我想这取决于您想要实现的目标。这是针对应用程序还是针对其他应用程序将使用的库?无论如何你不应该改变
ConfigServiceBootstrapConfiguration,但很难理解其意图是什么。 -
嗨 Dave,文档说我可以更改引导属性/yaml 中的 URI,因此我将其更改为使用 file:///my/file/path。这给出了一个错误,指出该文件不是受支持的协议。最后,我希望实现的是一个共享的配置服务器,但配置文件位于配置服务器所在框的文件夹中。然后,我创建的其他 spring boot 应用程序将连接到 cofig 服务器,就像它们在 git repo 时一样。我希望这是有道理的。
-
单元测试使用“file:”作为远程存储库,所以它应该可以工作。您必须显示堆栈跟踪或其他东西来诊断问题。另请注意,除非文件系统是共享的,否则您将拥有 SPOF。
-
嗨@DaveSyer,主帖中的编辑是否提供了足够的信息或者您想要更多信息?
-
这实际上不是堆栈跟踪。并且配置文件不是 Spring Cloud 配置文件(“uri”无论如何都没有绑定到配置服务器中的任何内容)。也许你可以扩大一点?
标签: spring spring-boot spring-cloud