Tomcat - запуск веб-приложений в определенном порядке
Я знаю, что спецификации Tomcat и Servlet не поддерживают запуск веб-приложений в определенном порядке.
Тем не менее, мне кажется, что это общий случай использования, и мне интересно, нашел ли кто-нибудь разумный обходной путь для этого.
У меня есть веб-приложение A, которое использует Spring Remoting для предоставления общего сервиса, клиентом которого является веб-приложение B. Веб-приложение B не может инициализироваться, если веб-приложение A не запущено. Однако мой Tomcat всегда запускает веб-приложения линейно, начиная с веб-приложения Б.
По инфраструктурным причинам они должны работать на одном сервере Tomcat.
Есть идеи?
Спасибо Рой
ОБНОВЛЕНИЕ -
Оказывается, в моем конкретном случае порядок не имеет значения. Причина в следующем: скажем, я использую один из методов ниже, чтобы запустить приложение A перед приложением B. Итак, приложение A запускается, но, поскольку удаленное взаимодействие Spring использует HTTP Invoker, порт HTTP еще не открыт (он не открывается пока все приложения не запустятся). Итак, A запустится, а B повиснет, потому что порт, который он ищет, еще не доступен. Doh.
Конечный результат - два отдельных экземпляра Tomcat.
6 ответов
У нас та же проблема, и для ее решения мы полагаемся на тот факт (я знаю, что он скользкий), когда приложения запускаются в том порядке, в котором они определены <tomcat_home>/conf/server.xml
,
Это, конечно, имеет недостаток в жестком кодировании приложений в server.xml
но мы можем жить с этим.
Вот еще один трюк с Linux.
Некоторые из наших приложений веб-сервисов не могут быть развернуты из-за ошибочного WSDL. Это происходит, если они развернуты или запущены после ряда других приложений. Порядок, в котором они запускаются, зависит от порядка, в котором контекстные XML-файлы находятся в /opt/apache-tomee/conf/Catalina/localhost
Может быть проверено с помощью "ls -1f
Msgstr "Простой" ls "дает отсортированный вывод.
Раньше это был порядок, в котором файлы были добавлены в этот каталог, но в файловых системах ext4 порядок основан на хэше имени файла. Это можно отключить следующим образом:
# tune2fs -O ^dir_index /dev/xyz
Теперь вы можете хотя бы самостоятельно решить, в каком порядке они будут запущены. Изменение порядка: переместить все файлы во временную папку, переместить их обратно в нужной последовательности.
Этого довольно легко достичь, если вам все равно, взломать код tomcat и создать свой собственный экземпляр Host
1) Создайте подкласс org.apache.catalina.core.StandardHost, скажем, MyHost:
class MyHost extends org.apache.catalina.core.StandardHost{
public MyHost (){
super();
//changing HashMap for a predictable ordered Map :)
this.children = new LinkedHashMap();
}
}
2) зарегистрируйте свой класс в теге xml Host вашего сервера ()
Невероятно, но это решает проблему до тех пор, пока все ваше веб-приложение объявлено в правильном порядке внутри тега Host:
<Host>
<context app1>
<context app2>
</Host>
Thaen app1 запустится до app2, независимо от того, какой SO вы использовали.
Старая нить, но...
Другой способ обойти это - создать собственный класс HostConfig, который сортирует веб-приложения так, как вам нужно.
public class OrderedHostConfig extends HostConfig {
@Override
protected String[] filterAppPaths(String[] unfilteredAppPaths) {
String[] files = super.filterAppPaths(unfilteredAppPaths);
Arrays.sort(files, compare());
return files;
}
private Comparator<String> compare() {
return (o1, o2) -> {
// Your own implementation
};
}
}
Затем вы можете ссылаться на этот класс в своем server.xml под определением Host.
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" hostConfigClass="your.package.OrderedHostConfig">
Вам нужно скомпилировать это в банку и сохранить в каталоге Tomcat /lib. В моем случае:
/ вар / библиотека /tomcat8/ библиотека
Мне нравится этот метод, потому что:
Порядок применяется только там, где это необходимо, но нет необходимости управлять всеми веб-приложениями вручную в определениях хоста с помощью контекста.
Поиск имени файла.war в базе кода также будет ссылаться на этот класс, что упрощает поиск переименованного файла.
Никаких изменений частных финальных полей для tomcat 8, см. Здесь
Поскольку ни один из вариантов не работал для Tomcat 9.0.19 (тот, который также упоминается @Luiz), мы использовали подход кода и заменили Tomcat StandardHost и HostConfig минимальными пользовательскими реализациями:
public class CustomTomcatHost extends StandardHost {
public CustomTomcatHost() {
super();
}
@Override
public void addLifecycleListener(LifecycleListener listener) {
if (listener instanceof HostConfig) {
listener = new OrderedHostConfig();
}
super.addLifecycleListener(listener);
}
}
Функция deployApps в HostConfig должна быть переопределена, чтобы сортировка работала для всего (включая файлы WAR в папке /webapps, а также для файлов XML дескриптора в папке configbase (например, conf/Catalina/localhost)):
public class OrderedHostConfig extends HostConfig {
public OrderedHostConfig() {
super();
}
public String[] prioritySort(String[] paths) {
if (paths == null) return null;
Arrays.sort(paths, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b); //TODO: sort paths based on your criteria
}
});
return paths;
}
@Override
protected void deployApps() {
File appBase = host.getAppBaseFile();
File configBase = host.getConfigBaseFile();
String[] apps = prioritySort(filterAppPaths(appBase.list()));
// Deploy XML descriptors from configBase
deployDescriptors(configBase, prioritySort(configBase.list()));
// Deploy WARs
deployWARs(appBase, apps);
// Deploy expanded folders
deployDirectories(appBase, apps);
}
}
Затем мы поместили новые классы в новый файл jar в каталоге Tomcat /lib и изменили файл conf/server.xml, чтобы заменить класс хоста нашей собственной реализацией:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" className="com.example.CustomTomcatHost" >
Во время запуска Tomcat загрузил все компоненты в нужном порядке.
В теории вы могли бы породить Runnable
от ExecutorService
в contextInitialized()
который, в свою очередь, проверяет доступность другого веб-приложения через определенные промежутки времени (возможно, с помощью HTTP HEAD
запрос?). Как только другое веб-приложение будет доступно, установите некоторый атрибут в контексте сервлета, который указывает на это. Добавить Filter
который проверяет наличие этого атрибута и соответственно блокирует / продолжает запросы.
Я знаю, что этот вопрос немного устарел, но я нашел его, пытаясь сделать то же самое, и подумал, что я обновлюсь с лучшим решением...
Вы можете определить несколько сервисов в вашем server.xml, которые работают на разных портах. Сервисы запускаются последовательно в порядке их появления в server.xml. Это означает, что у вас может быть, например, служба конфигурации, работающая в первой службе, а затем приложения, которые зависят от нее, во второй (для остальных я использую одну по умолчанию Catalina...)
Вы можете увидеть больше информации здесь: http://wiki.apache.org/tomcat/FAQ/Miscellaneous
И это сервис, который я включаю перед службой Catalina:
<Service name="ConfigService">
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8444" />
<Engine name="ConfigServiceEngine" defaultHost="localhost">
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
<Context path="/" reloadable="true" docBase="/path/to/your/service/directory" />
</Host>
</Engine>
</Service>
Как вы можете видеть, я использую docbase, а не appBase, но вы сможете настроить другую appBase, если хотите...
Внимание: важно изменить название службы и двигателя.
НТН
Вот хороший трюк, который я использую для создания 2 уровней загрузки веб-приложений. на каждом уровне порядок не гарантируется. Это зависит от того факта, что tomcat будет загружать первые дескрипторы контекста из tomcat/conf/[Engine Name]/[Host Name] и только затем контексты из атрибута appBase элемента Host в server.xml
Просто добавьте следующий код в веб-приложение, которое вы хотите загрузить на 2-м уровне (т.е. позже)
File contextDescriptor = new File(getParameter("catalina.home"),"/conf/Catalina/localhost/mywebapp.xml");
contextDescriptor.deleteOnExit();
Может ли быть так, что они запускаются в том порядке, в котором они развернуты?
Итак, если у меня четыре приложения: 1, 2, 3, 4, и я развертываю их в следующем порядке: 1, 2, 4 (перезапустить tomcat), 3 (перезапустить). Что он где-то кеширует, чтобы проекты всегда запускались в таком порядке? Итак, 1, 2, 4, 3. Это происходит здесь. Не уверен, но может кому-то это поможет.