java 根据在应用程序 war 文件之外指定的属性加载变量 spring applicationContext.xml 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4044015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
loading a variable spring applicationContext.xml file based on a property specified outside of the app war file?
提问by shsteimer
I have a need to change the spring applicationContext.xml file that is used based upon a property, this property MUSTbe defined somewhere outside of the war file (ie. it can't be in web.xml). Currently, I've arrived at the following solution (see my answer below), wondering if there's a better way to do this?
我需要更改基于属性使用的 spring applicationContext.xml 文件,该属性必须在 war 文件之外的某处定义(即它不能在 web.xml 中)。目前,我已经找到了以下解决方案(请参阅下面的答案),想知道是否有更好的方法来做到这一点?
回答by shsteimer
there are 4 parts to my solution. first, in web.xml of my application I define the following:
我的解决方案有 4 个部分。首先,在我的应用程序的 web.xml 中,我定义了以下内容:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation1</param-name>
<param-value>classpath:applicationContext-1.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation2</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>com.my.package.MyContextLoaderListener</listener-class>
</listener>
Then I extend ContextLoaderListener
然后我扩展 ContextLoaderListener
package com.my.package;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;
public class MyContextLoaderListener extends ContextLoaderListener {
@Override
protected ContextLoader createContextLoader() {
return new MyContextLoader();
}
}
and ContextLoader
和上下文加载器
package com.my.package;
import javax.servlet.ServletContext;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoader;
public class LnvContextLoader extends ContextLoader {
private static final String APP_CONTEXT_PROP = "MY_CONTEXT_LOAD_PARAM";
@Override
protected void customizeContext(ServletContext servletContext,
ConfigurableWebApplicationContext wac) {
//check for system property first, if not defined, check for env variable
String appContextParam = System.getProperty(APP_CONTEXT_PROP);
if(appContextParam==null)
{
appContextParam = System.getenv(APP_CONTEXT_PROP);
}
if(appContextParam!=null && !appContextParam.equals("")){
String initParam = servletContext.getInitParameter(appContextParam);
wac.setConfigLocation(initParam);
}
}
}
and finally, in my tomcat startup, I define the environment variable in setenv.bat
最后,在我的 tomcat 启动中,我在 setenv.bat 中定义了环境变量
set MY_CONTEXT_LOAD_PARAM=contextConfigLocation1
this solution loads it from an environment variable, but the code is flexible and allows it to be set in a system property instead.
此解决方案从环境变量加载它,但代码很灵活,并允许将其设置在系统属性中。
回答by Michael Wiles
Have you considered using the beanRefContext approach. (ContextSingletonBeanFactoryLocator). This way you can configure your spring config files (and their names) via another spring config file.
您是否考虑过使用 beanRefContext 方法。(ContextSingletonBeanFactoryLocator)。通过这种方式,您可以通过另一个 spring 配置文件配置您的 spring 配置文件(及其名称)。
Then you can paramaterise that file by whatever means you deem appropriate and switch the file names that way.
然后,您可以通过任何您认为合适的方式对该文件进行参数化,并以这种方式切换文件名。
The file looks like this:
该文件如下所示:
<beans>
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="${NameOfBeanConfigFile}" />
</bean>
</beans>
And you can use PropertyPlaceHolderConfigurer to set the value of NameOfBeanConfigFile.
您可以使用 PropertyPlaceHolderConfigurer 来设置 NameOfBeanConfigFile 的值。
I like this approach as it means I can mix static bean config file names with dynamic bean config file names and thus don't have to duplicate bean config.
我喜欢这种方法,因为这意味着我可以将静态 bean 配置文件名与动态 bean 配置文件名混合使用,因此不必重复 bean 配置。
When I had to do a similar thing I would parameterise via a config file loaded as a URL resource (via jndi)
当我不得不做类似的事情时,我会通过作为 URL 资源加载的配置文件进行参数化(通过 jndi)
回答by Guillaume
If you load your application context through the classpath, you can override it by placing another version of the applicationContext.xml in the server's classpath.
如果您通过类路径加载应用程序上下文,则可以通过在服务器的类路径中放置另一个版本的 applicationContext.xml 来覆盖它。
My solution would be to have a very simple applicationContext, that includes the real application context :
我的解决方案是拥有一个非常简单的 applicationContext,其中包括真正的应用程序上下文:
applicationContext.xml :
applicationContext.xml :
<beans>
<import resource="classpath:realContext.xml"/>
</beans>
If you want another context, add an applicationContext.xml to your server's classpath with :
如果您需要另一个上下文,请使用以下命令将 applicationContext.xml 添加到您的服务器的类路径:
<beans>
<import resource="classpath:realContext2.xml"/>
</beans>
And have realContext.xml and realContext2.xml packaged in your WAR. No need for fancy context listener.
并将 realContext.xml 和 realContext2.xml 打包在您的 WAR 中。不需要花哨的上下文侦听器。
Just my opinion, but I quite dislike to have WARs that are not self contained. I find it very convinient to have a single unit of deployement. So I would prefer to create 2 different versions of my WAR during the build process, one for each needed configuration.
只是我的意见,但我非常不喜欢有非独立的 WAR。我发现拥有一个部署单元非常方便。所以我更愿意在构建过程中创建 2 个不同版本的 WAR,每个需要的配置一个。
Another solution, if you want to load a different bean depending on a given property, you can use a PropertyPlaceholderConfigurer and put the name of the bean as a property :
另一种解决方案,如果您想根据给定的属性加载不同的 bean,您可以使用 PropertyPlaceholderConfigurer 并将 bean 的名称作为属性:
<beans>
<bean id="bean1" .../>
<bean id="bean2" .../>
<bean id="otherBean">
<property name="injectDifferentBean" ref="${property.containing.bean.name" />
</bean>
</beans>
and a property file with :
和一个属性文件:
property.containing.bean.name=bean1
or
或者
property.containing.bean.name=bean2