java Tomcat 中配置与 WAR 分离的优雅方式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1719857/
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
Elegant ways to separate configuration from WAR in Tomcat
提问by Nigel
I am trying to find the best way to pass complex configurations in a Spring webapp running in Tomcat. Currently I use JNDI to pass data sources and strings from the Tomcat context into the webapp, and this works well.
我试图找到在 Tomcat 中运行的 Spring webapp 中传递复杂配置的最佳方法。目前我使用 JNDI 将数据源和字符串从 Tomcat 上下文传递到 web 应用程序中,这很有效。
But, lets say I need to select the implementation of a notification service. There is no way that Spring can conditionally select which bean to instantiate (although in the past I have used a JNDI string to import a predefined configuration of beans by setting contextConfigLocation).
但是,假设我需要选择通知服务的实现。Spring 无法有条件地选择要实例化的 bean(尽管过去我使用 JNDI 字符串通过设置 contextConfigLocation 来导入 bean 的预定义配置)。
I've also seen many webapps which supply a configuration tool which will create a custom WAR file. In my opinion this is bad form, if for no other reason than it prevents the redeployment of WARs from upstream without many checks to ensure all the configuration has been re-applied.
我还看到许多 webapps 提供了一个配置工具,可以创建一个自定义的 WAR 文件。在我看来,这是一种糟糕的形式,如果没有其他原因,它会阻止从上游重新部署 WAR,而没有进行许多检查以确保所有配置都已重新应用。
Ideally I would be able to supply a Spring XML file which existed on the filesystem, outside of the webapp. But, the spring import directive does not seem to resolve ${} variables, making it impossible to supply customisations.
理想情况下,我将能够提供一个存在于文件系统上的 Spring XML 文件,位于 webapp 之外。但是,spring import 指令似乎无法解析 ${} 变量,因此无法提供自定义。
Are there any techniques I can employ here to properly separate complex configuration from the webapp?
我可以在这里使用任何技术来正确地将复杂的配置与 webapp 分开吗?
采纳答案by candiru
If I have a specific set of beans that I'd like to configure, and this configuration must be separated from the WAR file, I usually do the following:
如果我有一组特定的 bean 想要配置,并且该配置必须与 WAR 文件分开,我通常会执行以下操作:
In applicationContext.xml:
在applicationContext.xml 中:
<!-- here you have a configurer based on a *.properties file -->
<bean id="configurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file://${configDir}/configuration.properties"/>
<property name="ignoreResourceNotFound" value="false" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
<property name="searchSystemEnvironment" value="false" />
</bean>
<!-- this is how you can use configuration properties -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${smtp.host}"/>
</bean>
In configuration.properties:
在configuration.properties 中:
smtp.host=smtp.your-isp.com
You also need to start Tomcat with -DconfigDir=/path/to/configuration/directory
您还需要使用 -DconfigDir=/path/to/configuration/directory 启动 Tomcat
回答by tafit3
If you are using Spring 3, you can take advantage of the Spring Expression Language. Let's say you have two applications app1.war and app2.war and they require a properties file named config.properties. The applications will be deployed with context paths /app1 and /app2.
如果您使用的是 Spring 3,则可以利用 Spring 表达式语言。假设您有两个应用程序 app1.war 和 app2.war,它们需要一个名为 config.properties 的属性文件。应用程序将使用上下文路径 /app1 和 /app2 进行部署。
Create two directories app1 and app2 in a common directory, eg. C:\myConfig\app1 and C:\myConfig\app2.
在一个公共目录中创建两个目录 app1 和 app2,例如。C:\myConfig\app1 和 C:\myConfig\app2。
Put config.properties inside app1 and another config.properties inside app2.
将 config.properties 放在 app1 中,将另一个 config.properties 放在 app2 中。
Then create a file ${CATALINA_HOME}/conf/[enginename]/[hostname]/context.xml.default with the contents:
然后创建一个包含以下内容的文件 ${CATALINA_HOME}/conf/[enginename]/[hostname]/context.xml.default:
context.xml.default:
context.xml.default:
<Context>
<Parameter name="myConfigDirectory" value="C:/myConfig" override="false"/>
</Context>
The parameter myConfigDirectory will be available to all the applications on the host. It is better to create this parameter in context.xml.default rather than in server.xml, because the file can be changed later without restarting tomcat.
参数 myConfigDirectory 将可用于主机上的所有应用程序。最好在context.xml.default 中而不是在server.xml 中创建此参数,因为稍后无需重新启动tomcat 即可更改文件。
In the applicationContext.xml inside war you can access config.properties using the SpEL expression: "#{contextParameters.myConfigDirectory + servletContext.contextPath}/config.properties", so for example you can write:
在 war 中的 applicationContext.xml 中,您可以使用 SpEL 表达式访问 config.properties:“#{contextParameters.myConfigDirectory + servletContext.contextPath}/config.properties”,例如您可以编写:
applicationContext.xml:
应用上下文.xml:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:#{contextParameters.myConfigDirectory + servletContext.contextPath}/config.properties" />
</bean>
The expression will get expanded to C:/myConfig/app1 for application with contextPath /app1, and C:/myConfig/app2 for application with contextPath /app2. This will make the applications access the config.properties file based on their contextPath.
对于具有 contextPath /app1 的应用程序,表达式将扩展为 C:/myConfig/app1,对于具有 contextPath /app2 的应用程序,表达式将扩展为 C:/myConfig/app2。这将使应用程序根据它们的 contextPath 访问 config.properties 文件。
回答by Thorbj?rn Ravn Andersen
If you want to be fully portable between web containers you cannot rely on anything outside your WAR-file. In Tomcat the SecurityManager allows you to discover the physical location on disk where your code is deployed, and you can then use that knowledge to navigate the disk to a location where your configuration file is placed.
如果您想在 Web 容器之间完全可移植,则不能依赖 WAR 文件之外的任何内容。在 Tomcat 中,SecurityManager 允许您发现部署代码的磁盘上的物理位置,然后您可以使用该知识将磁盘导航到放置配置文件的位置。
See e.g. Determine location of a java class loaded by Matlab

