既存のSpring WebアプリがWARファイルとしてAmazon Elastic Beanstalkにデプロイされています。現在、プロパティファイルをhttpリソースとしてロードして、プロパティプレースホルダーの構成解決の単一のソースを提供しています。 gitバージョン管理などのメリットを得るために、これを新しいSpring Cloud構成サーバーに置き換えることを検討しています。
ただし、ドキュメント( http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html )は、Spring Bootクライアントアプリケーションのみを説明しているようです。既存のWebアプリでSpring Cloud Config Clientをセットアップすることは可能ですか? Bootstrap親アプリケーションコンテキストなどを手動でセットアップする必要がありますか?この例はありますか?現在のSpring構成はXMLベースです。
同様の要件があります。 Spring XML構成を使用していくつかのBeanを定義するWebアプリケーションがあり、プロパティの値は.propertyファイルに格納されています。要件は、開発中に構成をハードディスクからロードし、本番環境のSpring Cloud Configサーバーからロードすることです。
私の考えは、PropertyPlaceholderConfigurerに2つの定義を持たせることです。最初のものは、ハードディスクから設定をロードするために使用されます:
<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>
2番目のものは、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>
借り換え: https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html
Root WebApplicationContext
およびServlet WebApplicationContext
は、環境を使用し、スプリングプロファイルに基づいてPropertySourcesを初期化します。非スプリングブートアプリの場合は、これらをカスタマイズして、Config Serverからプロパティを取得し、プロパティが変更されるたびにBeanを更新する必要があります。以下は、SpringMVCで設定を機能させるために必要な変更です。 spring.profile.active
のシステムプロパティも必要です。
CustomBeanFactoryPostProcessor
を作成し、すべてのBean定義でlazyInit
を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);
}
}
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);
}
}
カスタムApplicatonContextInitializer
を作成し、initialize
メソッドの代わりにStandardServletEnvironment
の代わりにcustom Enviroment
を設定します。
public class ConfigAppContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setEnvironment(new CloudEnvironment());
}
}
web.xml
とapplication context
の両方にこのカスタムコンテキスト初期化子を使用するには、servlet 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>
更新エンドポイントを作成した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";
}
}
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();
}
}
Spring Bootで「機能する」ものはすべて、実際には何らかの構成にすぎません。結局のところ、これはすべてSpringアプリケーションです。したがって、おそらくBootが自動的に行うすべてを手動で設定できると思いますが、実際にこの特定の角度を試している人はいません。 bootstrap=アプリケーションコンテキストを作成することは確かに望ましいアプローチですが、ユースケースによっては、プロパティソースロケーターが十分に早く実行されることを確認すると、単一のコンテキストで動作する場合があります。
非Spring(または非Spring Boot)アプリは、構成サーバー内のプレーンテキストまたはバイナリファイルにアクセスできます。例えば。春には、@PropertySource
のようなURLであるリソースの場所(http://configserver/{app}/{profile}/{label}/application.properties
またはhttp://configserver/{app}-{profile}.properties
。すべてユーザーガイドに記載されています。
Dave Syerの優れた回答についてコメントするのに十分なポイントがないため、回答として投稿します。提案されたソリューションを実稼働環境で実装しましたが、期待どおりに機能しています。新しいアプリはBootを使用して記述されており、レガシーアプリはSpringを使用していますが、ブートは使用していません。 Spring Cloud Configを使用して、両方のプロパティを提供するプロパティサービスを作成できました。変更は最小限でした。レガシープロパティファイルをwarファイルからプロパティサービスgitリポジトリに移動し、クラスパス参照からDaveが説明するようにプロパティ定義をURLに変更し、クラスパスと同様にシステム環境変数を挿入しました。簡単で効果的でした。
<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" />
ここで提供されたアイデアに基づいて、Spring Bootなしでspring-cloud-zookeeperを使用するためのソリューションを見つけました https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html
ニーズに合わせて簡単に更新し、Spring Cloud Config Serverを使用する必要があります(Zookeeperではなくサーバーからファイルをロードするには、CloudEnvironementクラスを更新する必要があります)
まず、PropertySource(Zookeeperからの例)を作成するCloudEnvironementクラスを作成します。
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クラスを作成します。Webアプリケーションの起動時にZookeeperからPropertySourceをロードし、Spring Bootのbootstrap=マジックを置き換えます:
MyConfigurableWebApplicationContext.Java
public class MyConfigurableWebApplicationContext extends XmlWebApplicationContext {
@Override
protected ConfigurableEnvironment createEnvironment() {
return new CloudEnvironment();
}
}
最後に、web.xmlファイルに、MyConfigurableWebApplicationContextクラスを使用してCloudEnvironementをブートストラップするための次のcontext-paramを追加します。
<context-param>
<param-name>contextClass</param-name>
<param-value>com.kiabi.config.MyConfigurableWebApplicationContext</param-value>
</context-param>
標準のプロパティファイルコンフィギュレータを使用する場合は、ローカルファイルとZookeeperの両方にプロパティを設定できるように、ロードする必要があります。
これらすべてが機能するには、クラスパスにspring-cloud-starter-zookeeper-configとcurator-framework 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>