没有Spring Boot的Spring Cloud Config客户端

Dav*_*ary 31 spring spring-cloud

我们将现有的Spring Web应用程序部署为Amazon Elastic Beanstalk中的WAR文件.目前,我们将属性文件作为http资源加载,以便为我们提供单一的属性占位符配置解析源.我正在调查用新的Spring云配置服务器替换它,以便为我们提供git版本控制等的好处.

但是文档(http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html)似乎只描述了一个Spring Boot客户端应用程序.是否可以在现有的Web应用程序中设置Spring Cloud Config Client?我是否需要手动设置Bootstrap父应用程序上下文等 - 这是否有任何示例?我们当前的spring配置是基于XML的.

Gri*_*pal 7

参考:https : //wenku.baidu.com/view/493cf9eba300a6c30d229f49.html

Root WebApplicationContext并且Servlet WebApplicationContext使用 Environment 并根据 spring 配置文件初始化 PropertySources。对于非 spring 启动应用程序,我们需要自定义这些以从 Config Server 获取属性并在属性更改时刷新 bean。以下是使配置在 SpringMVC 中工作所需的更改。您还需要一个系统属性spring.profile.active

  1. 创建一个CustomBeanFactoryPostProcessor并将lazyInit所有 bean 定义设置为 true 以延迟初始化所有 bean,即 bean 仅在请求时初始化。

    @Component
    public class AddRefreshScopeProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
    
    private static ApplicationContext applicationContext;
    
    @SuppressWarnings("unchecked")
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
        String[] beanNames = applicationContext.getBeanDefinitionNames();
        for(int i=0; i<beanNames.length; i++){
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanNames[i]);
            beanDef.setLazyInit(true);
            beanDef.setScope("refresh");
        }
    }
    
    @Override
    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        applicationContext = context;
    }
    
    /**
     * Get a Spring bean by type.
     * 
     * @param beanClass
     * @return
     */
    public static <T> T getBean(Class<T> beanClass) {
        return applicationContext.getBean(beanClass);
    }
    
    /**
     * Get a Spring bean by name.
     * 
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个自定义类来扩展StandardServletEnvironment和覆盖initPropertySources加载其他 PropertySources的方法(来自配置服务器)。

     public class CloudEnvironment extends StandardServletEnvironment {
    
      @Override
        public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {
     super.initPropertySources(servletContext,servletConfig);
     customizePropertySources(this.getPropertySources());
       }
    
    @Override
      protected void customizePropertySources(MutablePropertySources propertySources) {
        super.customizePropertySources(propertySources);
        try {
          PropertySource<?> source = initConfigServicePropertySourceLocator(this);
          propertySources.addLast(source);
    
        } catch (
    
        Exception ex) {
          ex.printStackTrace();
        }
      }
    
      private PropertySource<?> initConfigServicePropertySourceLocator(Environment environment) {
    
        ConfigClientProperties configClientProperties = new ConfigClientProperties(environment);
        configClientProperties.setUri("http://localhost:8888");
        configClientProperties.setProfile("dev");
        configClientProperties.setLabel("master");
        configClientProperties.setName("YourApplicationName");
    
        System.out.println("##################### will load the client configuration");
        System.out.println(configClientProperties);
    
        ConfigServicePropertySourceLocator configServicePropertySourceLocator =
            new ConfigServicePropertySourceLocator(configClientProperties);
    
        return configServicePropertySourceLocator.locate(environment);
        }
    
      }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 创建自定义ApplicatonContextInitializer并覆盖initialize方法以设置custom Enviroment而不是StandardServletEnvironment

    public class ConfigAppContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.setEnvironment(new CloudEnvironment());
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 修改web.xml为使用两个这样的自定义上下文初始化application contextservlet context

    <servlet>
        <servlet-name>dispatcher</servlet-name>
            <servlet-class>
                org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
        <init-param>
            <param-name>contextInitializerClasses</param-name>
            <param-value>com.my.context.ConfigAppContextInitializer</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <context-param>
        <param-name>contextInitializerClasses</param-name>
        <param-value>com.my.context.ConfigAppContextInitializer</param-value>
    </context-param>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </context-param>
    
    Run Code Online (Sandbox Code Playgroud)

  5. 要刷新创建了刷新端点的 bean,您还需要刷新application Context.

    @Controller
    public class RefreshController {
    
    @Autowired
    private RefreshAppplicationContext refreshAppplicationContext;
    
    @Autowired
    private RefreshScope refreshScope;
    
    @RequestMapping(path = "/refreshall", method = RequestMethod.GET)
    public String refresh() {
        refreshScope.refreshAll();
        refreshAppplicationContext.refreshctx();
        return "Refreshed";
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)

刷新应用程序上下文.java

@Component
public class RefreshAppplicationContext implements ApplicationContextAware {

    private ApplicationContext applicationContext;
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }


    public void refreshctx(){
        ((XmlWebApplicationContext)(applicationContext)).refresh();
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我有类似的需求;我有一个 Web 应用程序,它使用 Spring XML 配置来定义一些 bean,属性的值存储在 .property 文件中。要求是在开发过程中从硬盘加载配置,在生产环境中从 Spring Cloud Config 服务器加载。

我的想法是对 PropertyPlaceholderConfigurer 有两个定义;第一个将用于从硬盘加载配置:

        <bean id="resources" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" doc:name="Bean">
        <property name="locations">
            <list>
                <value>dcm.properties</value>
                <value>post_process.properties</value>
            </list>
        </property>
    </bean>
Run Code Online (Sandbox Code Playgroud)

第二个将从 Spring Config Server 加载 .properties :

    <bean id="resources" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" doc:name="Bean">
        <property name="locations">
            <list>
                <value>http://localhost:8888/trunk/dcm-qa.properties</value>
            </list>
        </property>
    </bean>
Run Code Online (Sandbox Code Playgroud)


Dav*_*yer 2

Spring Boot“正常工作”的所有内容实际上只不过是一些配置。归根结底,这只是一个 Spring 应用程序。因此,我相信您可能可以手动设置 Boot 自动为您完成的所有操作,但我不知道有人真正尝试过这个特定的角度。创建引导应用程序上下文当然是首选方法,但根据您的用例,如果您确保属性源定位器足够早地执行,您可能会使其与单个上下文一起工作。

非 Spring(或非 Spring Boot)应用程序可以访问配置服务器中的纯文本或二进制文件。例如,在 Spring 中,您可以将 a@PropertySource与 URL 形式的资源位置一起使用,例如http://configserver/{app}/{profile}/{label}/application.propertieshttp://configserver/{app}-{profile}.properties。用户指南中涵盖了所有内容。

  • Dave @dave,您能否提供有关如何继续此操作的更多具体信息?如果配置服务器能够轻松地与现有的 spring mvc 应用程序集成,它将获得更广泛的受众。 (10认同)
  • @dave-syer你的回答不是特别有帮助。当然,OP 问这是否可能,所以“是”可能是正确的。总的来说,Spring在这里所采取的方向并不令人满意。XML 配置的消失和对 Spring Boot 的依赖使适应变得痛苦。 (4认同)
  • 有人让它运行吗?很遗憾看到一切都只是从 Spring Boot 的角度记录下来:( (3认同)
  • 我公司的几个客户正在寻找一种“爬行-行走-运行”方法,客户希望在不“启动”其应用程序的情况下迁移到配置服务。这对于最初采用来说是一个主要的痛苦。 (3认同)
  • 我同意 cmadsen 的观点,我不介意使用 spring boot 作为配置服务器本身,因为这将是我们系统中的一个新组件,但配置客户端确实应该能够轻松地与现有代码一起使用。毕竟它应该是一个“云”项目,因此与部署到已建立的云环境(例如 Elastic Beanstalk)中的标准 Spring Web 应用程序集成似乎是一个常见的用例。 (2认同)