从.war文件中外部化Tomcat webappconfiguration

我在configurationTomcat 7中的webapp时遇到了麻烦。在我的war文件中,有一个属性文件myApp / WEB-INF / classes / myProps.props,它包含特定于环境的特性。 我试图覆盖服务器上的configuration文件,以便相同的战争文件将部署到多个环境。

我听说有一种方法可以在tomcat / conf / Catalina / myApp中使用replaceconfiguration文件。 这是我无法解决的方法。

而且,myApp.war是运行在同一个tomcat服务器上的许多程序之一,并且它不能作为localhost运行。 我想能够解决这个问题的几个Web应用程序。

Server version: Apache Tomcat/7.0.23 Server built: Nov 20 2011 07:36:25 Server number: 7.0.23.0 OS Name: Linux 

你的tomcat/conf/Catalina/<host>可以包含上下文描述符,可以让你configuration很多东西,包括定义“环境条目”,这些条目可以通过JNDI从Java访问。 有很多方法可以使用它。 就我个人而言,我设置了一个环境条目,这是我的属性文件的文件系统path。 我的应用程序是为检查此条目而构build的,如果它不存在,请在类path中查找该文件。 这样,在dev中,我们在classpath上有开发属性,但是当我们构build和部署时,我们将它指向一个外部文件。

在Tomcat网站上configuration上下文有很好的文档。 请参阅“定义上下文”一节,了解如何创build文件以及放置位置的详细信息。

例如,如果您的主机名为“myHost”,并且您的应用程序是webapps目录中名为“myApp.war”的war文件,那么您可以使用以下内容创buildtomcat/conf/Catalina/myHost/myApp.xml

 <Context> <Environment name="configurationPath" value="/home/tomcat/myApp.properties" type="java.lang.String"/> </Context> 

然后从你的代码中,你可以对java:comp/env/configurationPath (这里95%的确定性)进行JNDI查找来获得该string值。

我喜欢.properties文件,而不是

  • JNDI – 为什么在程序configuration期间构build复杂对象而不是初始化时间?
  • 系统属性 – 不能在单个Tomcat中单独configuration相同WAR的几个实例
  • 上下文参数 – 它们只能在javax.servlet.Filterjavax.servlet.ServletContextListener访问,我不方便

Tomcat 7 上下文保存Loader元素。 根据文档部署描述符( <Context>标签中)可以放置在:

  • $CATALINA_BASE/conf/server.xml – 坏 – 要求服务器重新启动,以重新configuration
  • $CATALINA_BASE/conf/context.xml – bad – 在所有应用程序中共享
  • $CATALINA_BASE/work/$APP.war:/META-INF/context.xml – 坏 – 需要重新打包才能更改configuration
  • $CATALINA_BASE/work/[enginename]/[hostname]/$APP/META-INF/context.xml不错 ,但看到最后一个选项!
  • $CATALINA_BASE/webapps/$APP/META-INF/context.xml很好 ,但看到最后的select!
  • $CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml最好 – 完全不在应用程序中,并自动扫描更改!

Context可以容纳自定义的Loader org.apache.catalina.loader.VirtualWebappLoader (可以在现代Tomcat 7中使用,可以将自己的单独的类path添加到.properties )和Parameter (通过FilterConfig.getServletContext().getInitParameter(name) Environment (通过new InitialContext().lookup("java:comp/env").lookup("name")访问new InitialContext().lookup("java:comp/env").lookup("name") ):

 <Context docBase="${basedir}/src/main/webapp" reloadable="true"> <!-- http://tomcat.apache.org/tomcat-7.0-doc/config/context.html --> <Resources className="org.apache.naming.resources.VirtualDirContext" extraResourcePaths="/WEB-INF/classes=${basedir}/target/classes,/WEB-INF/lib=${basedir}/target/${project.build.finalName}/WEB-INF/lib"/> <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="${basedir}/target/classes;${basedir}/target/${project.build.finalName}/WEB-INF/lib"/> <JarScanner scanAllDirectories="true"/> <Parameter name="min" value="dev"/> <Environment name="app.devel.ldap" value="USER" type="java.lang.String" override="true"/> <Environment name="app.devel.permitAll" value="true" type="java.lang.String" override="true"/> </Context> 

如果你使用Spring并且它是XMLconfiguration:

 <context:property-placeholder location="classpath:app.properties"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@${db.host}:${db.port}:${db.user}"/> <property name="username" value="${db.user}"/> <property name="password" value="${db.pass}"/> </bean> 

使用Spring将上面的属性注入bean域是很容易的:

 @Value("${db.user}") String defaultSchema; 

而不是JNDI:

 @Inject ApplicationContext context; Enviroment env = context.getEnvironment(); String defaultSchema = env.getProperty("db.user"); 

还要注意EL允许这个(默认值和深度recursionreplace):

 @Value('${db.user:testdb}') private String dbUserName; <property name='username' value='${db.user.${env}}'/> 

也可以看看:

  • 添加一个目录到tomcat classpath
  • 我可以在Tomcat的每个应用程序基础上创build自定义类path吗?
  • 如何在Tomcat的webapp上下文之外读取一个属性文件
  • configurationTomcat以使用属性文件加载数据库连接信息
  • 应该在server.xml还是context.xml中设置数据库连接属性
  • 外部化Tomcatconfiguration

注意通过将类path扩展到活动目录,您还允许外部化任何其他configuration ,例如logging,auth,atc。 我以这种方式外部化logback.xml

更新 Tomcat 8更改 <Resources><Loader>元素的语法 ,相应的部分现在看起来像:

 <Resources> <PostResources className="org.apache.catalina.webresources.DirResourceSet" webAppMount="/WEB-INF/classes" base="${basedir}/target/classes" /> <PostResources className="org.apache.catalina.webresources.DirResourceSet" webAppMount="/WEB-INF/lib" base="${basedir}/target/${project.build.finalName}/WEB-INF/lib" /> </Resources> 

您可以尝试将您的configuration(属性文件)放在Apache Tomcat \ lib中的JAR文件中,并将其从Web应用程序中删除。 当Tomcat的类加载器在webapp中找不到你的configuration时,它会尝试在“lib”目录中find。 所以你可以将configuration外部化,只需将configuration移动到全局库目录(它是在其他web应用程序之间共享的)。

我刚刚在tomcat的bin文件夹中添加了setenv.bat或setenv.sh脚本。 像设置CLASSPATH = my-propery-folder一样设置classpathvariables

约翰