从.war文件外部化Tomcat webapp配置

mfa*_*mfa 33 linux configuration tomcat

我在Tomcat 7中配置webapp时遇到问题.在我的WAR文件中,有一个属性文件myApp/WEB-INF/classes/myProps.props,它包含特定于环境的属性.我试图覆盖服务器上的配置文件,以便相同的WAR文件将部署到多个环境.

我听说有一种方法可以使用替换配置文件tomcat/conf/Catalina/myApp.这是我无法搞清楚的方法.

此外,myApp.war是在同一个Tomcat服务器上运行的许多服务器之一,并且它不作为localhost运行.我希望能够为几个webapps解决这个问题.

Server version: Apache Tomcat/7.0.23
Server built:   Nov 20 2011 07:36:25
Server number:  7.0.23.0
OS Name:        Linux
Run Code Online (Sandbox Code Playgroud)

Rya*_*art 64

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

有关在Tomcat网站上配置上下文的良好文档.有关如何创建文件以及放置文件的位置的详细信息,请参阅定义上下文部分.

举个例子,如果你的主机的名称myHost和您的应用程序被命名为war文件myApp.warwebapps目录,那么你可以创建tomcat/conf/Catalina/myHost/myApp.xml与此内容:

<Context>
    <Environment name="configurationPath" value="/home/tomcat/myApp.properties" type="java.lang.String"/>
</Context>
Run Code Online (Sandbox Code Playgroud)

然后从您的代码中,您将执行JNDI查找java:comp/env/configurationPath(此处为95%确定性)以获取该字符串值.

  • 这确实是做@fma想要做的事情的正确方法. (4认同)

gav*_*koa 45

我喜欢.properties文件而不是文件

  • JNDI - 为什么在程序配置而不是初始化时间内构建复杂对象
  • 系统属性 - 您无法在单个Tomcat中单独配置多个相同WAR的实例
  • 上下文参数 - 它们只能访问javax.servlet.Filter,javax.servlet.ServletContextListener这对我来说很不方便

Tomcat 7 Context hold Loader元素.根据docs部署描述符(<Context>标签中的内容)可以放在:

  • $CATALINA_BASE/conf/server.xml - 糟糕 - 需要服务器重启才能重新读取配置
  • $CATALINA_BASE/conf/context.xml - 糟糕 - 在所有应用程序中共享
  • $CATALINA_BASE/work/$APP.war:/META-INF/context.xml - 糟糕 - 需要重新打包才能更改配置
  • $CATALINA_BASE/work/[enginename]/[hostname]/$APP/META-INF/context.xml- 很好,但看到最后一个选项!
  • $CATALINA_BASE/webapps/$APP/META-INF/context.xml- 很好,但看到最后一个选项!
  • $CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml- 最好 - 完全没有应用程序并自动扫描更改!

Context可以保存自定义Loader org.apache.catalina.loader.VirtualWebappLoader(在现代Tomcat 7中可用,您可以为您添加自己独立的类路径.properties),以及Parameter(通过访问FilterConfig.getServletContext().getInitParameter(name))和Environment(通过访问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>
Run Code Online (Sandbox Code Playgroud)

如果你使用Spring和它的XML配置:

<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>
Run Code Online (Sandbox Code Playgroud)

使用Spring将以上属性注入bean字段很容易:

@Value("${db.user}") String defaultSchema;
Run Code Online (Sandbox Code Playgroud)

而不是JNDI:

@Inject ApplicationContext context;
Enviroment env = context.getEnvironment();
String defaultSchema = env.getProperty("db.user");
Run Code Online (Sandbox Code Playgroud)

另请注意,EL允许这样做(默认值和深度递归替换):

@Value('${db.user:testdb}') private String dbUserName;

<property name='username' value='${db.user.${env}}'/>
Run Code Online (Sandbox Code Playgroud)

也可以看看:

注意通过将类路径扩展到实时目录,您还可以对任何其他配置进行外部处理,例如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>
Run Code Online (Sandbox Code Playgroud)