Внешняя конфигурация Tomcat

У меня есть конфигурация DataSource в context.xml. Можно ли не жестко кодировать параметры базы данных в этом файле? Например, используйте внешний файл свойств и загрузите из него параметры?

Что-то вроде:

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"/>

db.properties:

db.url=jdbc:oracle:thin:@server:1521:sid
db.user=test
db.pwd=test

Ответ 1

Как указано здесь, вы можете сделать это следующим образом.

1. Загрузите библиотеку tomcat, чтобы получить определение интерфейса, например, определяя зависимость от maven:

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-coyote</artifactId>
        <version>7.0.47</version>
    </dependency>

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;
    }
}

3.Put MyPropertyDecoder.class в папку tomcat7/lib
4.Define org.apache.tomcat.util.digester. Свойство PROPERTY_SOURCE: tomcat7/conf/catalina.properties:

org.apache.tomcat.util.digester.PROPERTY_SOURCE=com.mycompany.MyPropertyDecoder

5.Update your context.xml со свойствами vars

<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"
           ...  

6.Put application.properties файл где-нибудь в вашем проекте/контейнере
7. Убедитесь, что MyPropertyDecoder правильно читает application.properties
8.Enjoy!

PS Также существует аналогичный подход, описанный для tc Server.

Ответ 2

Легко с контекстные дескрипторы развертывания, которые выглядят так:

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

Есть несколько мест, где вы можете поместить эту конфигурацию, так как мой лучший вариант $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"))

См. обсуждение по адресу:

ОБНОВЛЕНИЕ Синтаксис изменения 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>

Ответ 3

Конечно, это возможно. Вы должны зарегистрировать ServletContextListener в своем web.xml следующим образом:

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

<listener>
    <listener-class>com.mycompany.servlets.ApplicationListener</listener-class>
</listener>

Источник 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
    }

}

И затем, где-то в коде веб-приложения для доступа к dataSource:

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

SomeDataSourceImpl - это конкретная реализация javax.sql.DataSource. Пожалуйста, сообщите, если вы не используете конкретные dataSource (например, ComboPooledDataSource для пула соединений) и не знаете, как его получить - Я опубликую, как обойти это.

some-data-source-alias - это просто String псевдоним (ключ) для вашего экземпляра dataSource в таблице атрибутов ServletContext. Хорошей практикой является предоставление псевдонимов с именем пакета, например com.mycompany.mywebapp.dataSource.

Надеюсь, что это поможет...

Ответ 4

Если это Tomcat 7, вы можете написать свои собственные переменные чтения org.apache.tomcat.util.IntrospectionUtils.PropertySource, написанные как "$ {...}" в context.xml. Вам необходимо установить системное свойство org.apache.tomcat.util.digester.PROPERTY_SOURCE, чтобы указать на реализацию PropertySource.