外部化Tomcat配置

nev*_*ver 17 tomcat

我在context.xml中有一个DataSource配置.是否有可能不对该文件中的数据库参数进行硬编码?例如,使用外部属性文件,并从中加载参数?

像这样的东西:

context.xml中:

  <Resource
  name="jdbc/myDS" auth="Container"
  type="javax.sql.DataSource"
  driverClassName="oracle.jdbc.OracleDriver"
  url="${db.url}"
  username="${db.user}"
  password="${db.pwd}"
  maxActive="2"
  maxIdle="2"
  maxWait="-1"/>
Run Code Online (Sandbox Code Playgroud)

db.properties:

db.url=jdbc:oracle:thin:@server:1521:sid
db.user=test
db.pwd=test
Run Code Online (Sandbox Code Playgroud)

Ant*_*nyi 11

如前所述在这里,您可以通过以下方式做到这一点.

1.下载tomcat库以获取接口定义,例如通过定义maven依赖项:

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-coyote</artifactId>
        <version>7.0.47</version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

2.下一步是按以下方式创建com.mycompany.MyPropertyDecoder:

import org.apache.tomcat.util.IntrospectionUtils;
public class MyPropertyDecoder implements IntrospectionUtils.PropertySource  {
    @Override
    public String getProperty(String arg0) {
        //TODO read properties here
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

3.将MyPropertyDecoder.class放入tomcat7/lib文件夹
4.定义org.apache.tomcat.util.digester.tomcat7/conf/catalina.properties中的 PROPERTY_SOURCE属性如下:

org.apache.tomcat.util.digester.PROPERTY_SOURCE=com.mycompany.MyPropertyDecoder
Run Code Online (Sandbox Code Playgroud)

5.使用属性变量更新context.xml

<Resource name="jdbc/TestDB"
           auth="Container"
           type="javax.sql.DataSource"
           username="root"
           password="${db.password}"
           driverClassName="com.mysql.jdbc.Driver"
           url="jdbc:mysql://localhost:3306/mysql?autoReconnect=true"
           ...  
Run Code Online (Sandbox Code Playgroud)

6.将application.properties文件放在项目/容器中的某个位置7.
确保MyPropertyDecoder正确读取application.properties
8.Enjoy!

PS此外,还有针对tc Server描述的类似方法.


gav*_*koa 5

使用上下文部署描述符很容易,它类似于:

<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)

您可以在几个地方放置此配置,我认为最好的选择是 $CATALINA_BASE/conf/[enginename]/[hostname]/$APP.xml

在上述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")

请参阅以下讨论:

UPDATE 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)


Yur*_*nyy 2

当然,这是可能的。你必须像这样注册ServletContextListenerweb.xml

<!-- at the beginning of web.xml -->

<listener>
    <listener-class>com.mycompany.servlets.ApplicationListener</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)

来源com.mycompany.servlets.ApplicationListener

package com.mycompany.servlets;

public class ApplicationListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // this method is invoked once when web-application is deployed (started)

        // reading properties file
        FileInputStream fis = null;
        Properties properties = new Properties();
        try {
            fis = new FileInputStream("path/to/db.properties")    
            properties.load(fis);
        } catch(IOException ex) {
            throw new RuntimeException(ex);
        } finally {
            try {
                if(fis != null) {
                    fis.close();
                }
            } catch(IOException e) {
                throw new RuntimeException(e);
            }
        }

        // creating data source instance
        SomeDataSourceImpl dataSource = new SomeDataSourceImpl();
        dataSource.setJdbcUrl(properties.getProperty("db.url"));
        dataSource.setUser(properties.getProperty("db.user"));
        dataSource.setPassword(properties.getProperty("db.pwd"));

        // storing reference to dataSource in ServletContext attributes map
        // there is only one instance of ServletContext per web-application, which can be accessed from almost anywhere in web application(servlets, filters, listeners etc)
        final ServletContext servletContext = servletContextEvent.getServletContext();
        servletContext.setAttribute("some-data-source-alias", dataSource);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        // this method is invoked once when web-application is undeployed (stopped) - here one can (should) implement resource cleanup etc
    }

}
Run Code Online (Sandbox Code Playgroud)

然后,在 Web 应用程序代码中的某个位置访问dataSource

ServletContext servletContext = ...; // as mentioned above, it should be accessible from almost anywhere
DataSource dataSource = (DataSource) servletContext.getAttribute("some-data-source-alias");
// use dataSource
Run Code Online (Sandbox Code Playgroud)

SomeDataSourceImpl是javax.sql.DataSource的一些具体实现。如果您不使用特定的DataSources(例如用于连接池的ComboPooledDataSource)并且不知道如何获取它,请告知 - 我将发布如何绕过它。

some-data-source-alias- 只是属性映射中实例String的别名(键)。好的做法是在别名前面加上包名,例如.DataSourceServletContextcom.mycompany.mywebapp.dataSource

希望这可以帮助...

  • 根据http://docs.oracle.com/javase/jndi/tutorial/beyond/env/source.html:可以在“jndi.properties”文件中指定“JNDI”资源,但它应该驻留在应用程序类路径或在“JAVA_HOME/lib/jndi.properties”中,这是相当有限的。看起来 Tomcat 在 `context.xml` 中仅使用 `JNDI` 功能,因此很可能不可能有像 `url="${db.url}"` 这样的东西引用来自某些外部文件的值。我见过这样的情况:`context.xml` 在打包到 `.war` 文件之前由 Ant 进行预处理。 (2认同)