Spring Boot配置服务器

10

我一直在尝试掌握位于此处的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;
}

最终,这样做达到了我想要的效果。 现在我很好奇这是否是我应该做的,或者我还有什么遗漏,而且这已经得到处理,只是我错过了它。

*****为满足Dave的要求编辑的信息*****

如果我删除文件属性源加载器并更新bootstrap.yml,

uri: 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协议为'file'时似乎并没有按预期运行。

******附加编辑*******

我对这个工作方式的理解是这样的: 示例项目依赖于spring-cloud-config-client构件,因此具有spring-cloud-config-server构件的传递依赖项。 客户端构件中的ConfigServiceBootstrapConfiguration.java创建了一个类型为ConfigServicePropertySourceLocator的属性源定位器bean。 config client构件中的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的连接。 我假设由于ConfigServicePropertySourceLocator中设置了uri属性,因此任何有效的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)

那并不是一个堆栈跟踪。而且配置文件也不是Spring Cloud配置文件(“uri”在配置服务器中默认情况下没有绑定到任何内容)。也许你可以再详细解释一下? - Dave Syer
你的“bootstrap.yml”片段只是说uri。所以你是在配置服务器的“bootstrap.yml”中设置了spring.cloud.config.uri,还是在客户端中设置?我有点困惑,而且你关于传递依赖项的描述是颠倒的:服务器依赖于客户端,而不是相反,而且spring.cloud.config.uri是客户端设置,而不是服务器设置。客户端不需要知道git。 - Dave Syer
我非常确定我所编写的类是必需的。因为ConfigServicePropertySourceLocator假定需要一个RestTemplate来获取属性文件。 - peekay
所以客户端有本地配置文件(而不是服务器)?然后这是正常的Spring Boot规则,你只需要为每个客户端设置spring.config.location。即使没有使用Spring Cloud,你也可以做到这一点,但是如果你正在使用Cloud,那么'bootstrap.yml'就可以了。最好的沟通方式是创建一个样例项目,并在某个地方发布它,同时提供完整的说明和/或测试。如果你能做到这一点,那么理解你的意图可能会更容易。 - Dave Syer
让我们在聊天中继续这个讨论 - peekay
显示剩余5条评论
3个回答

6

我昨天阅读了这个帖子,但它缺少一些重要信息。

如果您不想使用Git作为存储库,则需要配置Spring Cloud服务器以具有spring.profiles.active=native

查看spring-config-server代码以了解更多信息:

org.springframework.cloud.config.server.NativeEnvironmentRepository

 spring:
   application:
    name: configserver
  jmx:
    default_domain: cloud.config.server
  profiles:
    active: native
  cloud:
    config:
      server:
        file :
          url : <path to config files>  

4

我刚遇到了同样的问题。我希望配置服务器从本地文件系统中加载属性,而不是从git仓库中加载。以下配置在Windows上适用于我。

spring:  
  profiles:
    active: native
  cloud:
    config:
      server:
        native: 
          searchLocations: file:C:/springbootapp/properties/

假设属性文件位于 C:/springbootapp/properties/。
有关更多信息,请参阅Spring Cloud 文档配置全部清除

2

根据您的最新评论,我认为我有了最终解决方案。在configserver.yml文件中,我添加了以下内容:

spring.profiles.active: file
spring.cloud.config.server.uri: file://${user.home}/resources

在ConfigServerConfiguration.java文件中,我添加了以下内容:
@Configuration
@Profile("file")
protected static class SpringApplicationConfiguration {
@Value("${spring.cloud.config.server.uri}")
String locations;

@Bean
public SpringApplicationEnvironmentRepository repository() {
SpringApplicationEnvironmentRepository repo = new SpringApplicationEnvironmentRepository();
repo.setSearchLocations(locations);
return repo;
}
}

我可以通过以下方式查看属性:

curl localhost:8888/bar/default
curl localhost:8888/foo/development

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接