Внешняя настройка Tomcat webapp config из файла .war

У меня проблемы с настройкой веб-приложения в Tomcat 7. В моем WAR файле есть файл свойств myApp/WEB-INF/classes/myProps.props, и он содержит специфические для среды свойства. Я пытаюсь переопределить этот файл конфигурации на сервере, чтобы один и тот же WAR файл был развернут в нескольких средах.

Я слышал, что есть способ сделать это, используя файлы конфигурации замены в tomcat/conf/Catalina/myApp. Это метод, который мне трудно понять.

Кроме того, myApp.war является одним из многих, работающих на одном сервере Tomcat, и он не работает как myApp.war. Я хочу быть в состоянии решить эту проблему для нескольких веб-приложений.

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

Ответ 1

Ваш tomcat/conf/Catalina/<host> может содержать дескрипторы контекста, которые позволяют вам конфигурировать множество вещей, включая определение "записей среды", которые доступны из Java через JNDI. Есть много способов использовать его. Лично я установил запись среды, которая представляет собой путь файловой системы к моему файлу свойств. Мое приложение создано для проверки этой записи, и, если она не существует, вместо этого найдите файл в classpath. Таким образом, в dev у нас есть свойства dev прямо на пути к классам, но когда мы собираем и внедряем, мы указываем на внешний файл.

Там хорошая документация для настройки контекста на сайте Tomcat. См. Раздел " Определение контекста", где подробно описано, как создать файл и где его разместить.

Например, если ваш хост называется myHost а ваше приложение представляет собой файл war с именем myApp.war в каталоге webapps, то вы можете создать tomcat/conf/Catalina/myHost/myApp.xml со следующим содержимым:

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

Затем из вашего кода вы должны выполнить поиск JNDI для java:comp/env/configurationPath (здесь 95% -ная уверенность), чтобы получить это строковое значение.

Ответ 2

Мне нравятся файлы .properties вместо

  • JNDI - зачем строить сложный объект во время конфигурации программы, а не во время инициализации?
  • системные свойства - вы не можете отдельно настроить несколько экземпляров одной и той же WAR в одном Tomcat
  • параметры контекста - они доступны только в javax.servlet.Filter, javax.servlet.ServletContextListener которые могут быть неудобны

Tomcat 7 Context содержит элемент Loader. В соответствии с дескриптором развертывания документов (что в <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>

Если вы используете Spring и его XML config:

<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 вводить указанные выше свойства в поля компонента легко:

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

вместо JNDI:

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

Также обратите внимание, что EL допускает это (значения по умолчанию и глубокая рекурсивная замена):

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

<property name='username' value='${db.user.${env}}'/>

Смотрите также:

ПРИМЕЧАНИЕ. Расширяя classpath до действующего каталога, вы также разрешаете экстернилировать любые другие настройки, такие как logging, auth, atc. Я externilize 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>

Ответ 3

Вы можете попробовать разместить свою конфигурацию (файл свойств) в Apache Tomcat\lib в файле JAR и удалить ее из веб-приложения. Когда загрузчик класса Tomcat не найдет вашу конфигурацию в webapp, он попытается найти в каталоге "lib". Таким образом, вы можете экстернализировать свою конфигурацию, просто переместив конфигурацию в глобальный lib dir (она была распространена среди других webapps).

Ответ 4

Я только что добавил сценарий setenv.bat или setenv.sh в папку bin на tomcat. Установите переменную classpath как

set CLASSPATH=my-propery-folder