2015-02-06 99 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(); 
    } 
} 
相关问题