2015-02-06 71 views
23

我們有一個現有的Spring Web應用程序作爲WAR文件部署到Amazon Elastic Beanstalk中。目前我們將屬性文件加載爲http資源,爲我們提供了屬性佔位符配置解決方案的單一來源。我正在研究用新的spring雲配置服務器替換這個,以給我們git版本控制的好處等。沒有彈簧啓動的Spring Cloud Config客戶端

但是文檔(http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html)似乎只是描述Spring Boot客戶端應用程序。是否可以在現有的Web應用程序中設置Spring Cloud Config Client?我是否需要手動設置Bootstrap父應用程序上下文等 - 是否有任何這樣的例子?我們目前的彈簧配置是基於XML的。

+0

嗨。對此有何更新?我處於相同的情況 – 2015-07-28 12:54:31

+0

@David Geary有沒有想過這個? – Selwyn 2015-10-27 12:18:26

+0

對不起,我還沒有看過這個,因爲它需要一些手工努力才能在非彈簧啓動應用程序中執行此操作,從彈簧啓動中複製代碼等。不幸的是,Spring雲的東西似乎只專注於Spring Boot。 – 2015-10-28 16:23:53

回答

4

Spring Boot實際上只是一些配置。這一切都只是一個春天的應用程序在一天結束時。所以我相信你大概可以手動設置Boot的所有功能,但是我沒有意識到有人正在嘗試這個特定的角度。創建引導應用程序上下文肯定是首選方法,但根據您的使用情況,如果確保屬性源定位器足夠早地執行,您可以使用它來使用單個上下文。

非Spring(或非Spring Boot)應用程序可以訪問配置服務器中的純文本或二進制文件。例如。在Spring中,您可以使用@PropertySource,其資源位置是一個URL,如http://configserver/{app}/{profile}/{label}/application.propertieshttp://configserver/{app}-{profile}.properties。這一切都在用戶指南中介紹。

+5

Dave @dave,你能否提供更多關於如何繼續的信息?如果可以輕鬆地集成現有的彈簧mvc應用程序,配置服務器將獲得更廣泛的受衆。 – cmadsen 2015-02-10 08:21:42

+1

我同意cmadsen,我不介意爲配置服務器本身使用spring boot,因爲這將是我們系統中的一個新組件,但配置客戶端應該能夠很容易地與現有代碼一起使用。畢竟它應該是一個'雲'項目,因此與部署在已建立的雲環境中的標準Spring Web應用程序的集成(例如Elastic Beanstalk)似乎是一個常見用例。 – 2015-02-10 16:11:19

+0

要開始,請查看通過https://github.com/spring-cloud/spring-cloud-config/blob/master/spring-cloud-config-client/src/main/resources通過啓動自動加載的代碼/META-INF/spring.factories這些類是Spring-Cloud-Client的入口點。您可以忽略「RefreshAutoConfiguration」,「LifecycleMvcEndpointAutoConfiguration」和「RestartListener」。 – spencergibb 2015-02-10 21:11:23

3

我有類似的要求;我有一個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> 

第二個將加載從Spring配置服務器的.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> 
+0

現在我需要一個簡單的方法來添加重試。你將如何在代碼中添加該bean? – cerebrotecnologico 2017-04-11 17:16:38

+0

這不適合我。 localhost值不被應用程序使用 – Jay 2017-06-19 22:57:38

1

發帖的,因爲我不回答沒有足夠的觀點來評論Dave Syer的出色答案。我們在生產中實施了他提出的解決方案,並且按預期工作。我們的新應用程序使用Boot編寫,而我們的傳統應用程序使用Spring,但不啓動。我們能夠使用Spring Cloud Config創建一個爲兩者提供屬性的屬性服務。這些變化很小。我將遺留屬性文件從war文件移出到屬性服務git存儲庫,並將屬性定義從類路徑引用更改爲URL,因爲Dave描述並插入我們的系統環境變量,就像我們爲classpath所做的那樣。這很容易和有效。

<util:properties id="envProperties" location="https://properties.me.com/property-service/services-#{envName}.properties" /> 
<context:property-placeholder properties-ref="envProperties" ignore-resource-not-found="true" ignore-unresolvable="true" order="0" /> 
<util:properties id="defaultProperties" location="https://properties.me.com/property-service/services-default.properties" /> 
<context:property-placeholder properties-ref="defaultProperties" ignore-resource-not-found="true" ignore-unresolvable="true" order="10" /> 
+0

我發現它很有用。但我的問題是,每個環境中的服務器名稱會有所不同。我試圖從另一個屬性文件獲取服務器名稱,但它不起作用。 ,我需要像 \t \t 。我怎樣才能動態設置config.server.url?任何想法 – Vins 2017-12-14 04:02:44

1

我找到了一個解決方案,使用彈簧雲飼養員沒有Spring引導的基礎上,在這裏提供的想法https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html

它應該很容易更新,以滿足您的需求和使用Spring的雲配置服務器(在CloudEnvironement類需要進行更新,以從服務器,而不是動物園管理員)加載文件

首先,創建一個類CloudEnvironement將創建一個動物園管理員PropertySource(前):

CloudEnvironement。java的

public class CloudEnvironment extends StandardServletEnvironment { 

    @Override 
    protected void customizePropertySources(MutablePropertySources propertySources) { 
    super.customizePropertySources(propertySources); 
    try { 
     propertySources.addLast(initConfigServicePropertySourceLocator(this)); 
    } 
    catch (Exception ex) { 
     logger.warn("failed to initialize cloud config environment", ex); 
    } 
    } 

    private PropertySource<?> initConfigServicePropertySourceLocator(Environment environment) { 
    ZookeeperConfigProperties configProp = new ZookeeperConfigProperties(); 
    ZookeeperProperties props = new ZookeeperProperties(); 
    props.setConnectString("myzookeeper:2181"); 
    CuratorFramework fwk = curatorFramework(exponentialBackoffRetry(props), props); 
    ZookeeperPropertySourceLocator propertySourceLocator = new ZookeeperPropertySourceLocator(fwk, configProp); 
    PropertySource<?> source= propertySourceLocator.locate(environment); 
    return source ; 
    } 

    private CuratorFramework curatorFramework(RetryPolicy retryPolicy, ZookeeperProperties properties) { 
    CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder(); 
    builder.connectString(properties.getConnectString()); 
    CuratorFramework curator = builder.retryPolicy(retryPolicy).build(); 
    curator.start(); 
    try { 
     curator.blockUntilConnected(properties.getBlockUntilConnectedWait(), properties.getBlockUntilConnectedUnit()); 
    } 
    catch (InterruptedException e) { 
     throw new RuntimeException(e); 
    } 
    return curator; 
    } 

    private RetryPolicy exponentialBackoffRetry(ZookeeperProperties properties) { 
    return new ExponentialBackoffRetry(properties.getBaseSleepTimeMs(), 
     properties.getMaxRetries(), 
     properties.getMaxSleepMs()); 
    } 

} 

然後創建一個自定義的XMLWebApplicationContext類:它將使加載從動物園管理員的PropertySource當你的web應用啓動並更換彈簧引導的引導魔力:

MyConfigurableWebApplicationContext.java

public class MyConfigurableWebApplicationContext extends XmlWebApplicationContext { 

    @Override 
    protected ConfigurableEnvironment createEnvironment() { 
    return new CloudEnvironment(); 
    } 
} 

最後,在您的web.xml文件中添加以下上下文參數以使用y我們的MyConfigurableWebApplicationContext類並引導您的CloudEnvironement。

<context-param>   
     <param-name>contextClass</param-name> 
     <param-value>com.kiabi.config.MyConfigurableWebApplicationContext</param-value> 
    </context-param> 

如果你使用一個標準的屬性文件配置者,仍應被加載,所以你可以在這兩個本地文件和動物園管理員屬性。

對於這一切工作,你需要有彈簧雲起動動物園管理員,配置和策展人框架的jar在類路徑與他們的扶養,如果你使用Maven的,你可以添加以下到您的的pom.xml

<dependencyManagement> 
     <dependencies> 
      <dependency> 
       <groupId>org.springframework.cloud</groupId> 
       <artifactId>spring-cloud-zookeeper-dependencies</artifactId> 
       <version>1.1.1.RELEASE</version> 
       <type>pom</type> 
       <scope>import</scope> 
      </dependency> 
     </dependencies> 
    </dependencyManagement> 

    <dependencies> 
     <dependency> 
      <groupId>org.springframework.cloud</groupId> 
      <artifactId>spring-cloud-starter-zookeeper-config</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.curator</groupId> 
      <artifactId>curator-framework</artifactId> 
     </dependency> 
    </dependencies> 
1

Refrenced:https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html

根的WebApplicationContext和WebApplicationContext的使用環境和初始化基於彈簧輪廓PropertySources了Servlet。對於非彈簧啓動應用程序,我們需要自定義這些以從配置服務器獲取屬性,並在屬性發生更改時刷新Bean。以下是在SpringMVC中配置工作所做的更改。您還需要爲spring.profile.active

  1. 系統屬性創建CustomBeanFactoryPostProcessor和所有bean定義設置爲true lazyInit初始化所有的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); 
        } 
    } 
    
  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); 
        } 
    
        } 
    
  3. 創建自定義ApplicatonContextInitializer並重寫初始化方法來設置的自定義環境而不是StandardServletEnvironment的。

    public class ConfigAppContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { 
    
    @Override 
    public void initialize(ConfigurableApplicationContext applicationContext) { 
        applicationContext.setEnvironment(new CloudEnvironment()); 
        } 
    } 
    
  4. 修改web.xml以將此自定義上下文初始值設定項用於應用程序上下文和servlet上下文。

    <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> 
    

  5. 要刷新創建刷新終點,你還需要刷新應用程序上下文的bean。

    @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"; 
    } 
    

    }

RefreshAppplicationContext.java

@Component 
public class RefreshAppplicationContext implements ApplicationContextAware { 

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


    public void refreshctx(){ 
     ((XmlWebApplicationContext)(applicationContext)).refresh(); 
    } 
} 
相關問題