我知道Tomcat和Servlet规范do not support starting webapps in a particular order。
然而,在我看来,这似乎是一个常见的用例,我想知道是否有人发现了一个聪明的解决方法。
我有webapp A,它使用Spring Remoting来公开共享服务,其中webapp B是客户端。除非webapp A正在运行,否则Webapp B无法初始化。但是,我的Tomcat总是线性地启动webapps,从webapp B开始。
出于基础架构原因,我必须在同一个Tomcat服务器上运行它们。
有什么想法吗?
谢谢, 罗伊
更新 -
事实证明,在我的特定情况下,订单并不重要。原因是这样的:假设我使用下面的方法之一在应用程序B之前启动应用程序A.所以应用程序A启动,但是,由于Spring远程处理正在使用HTTP Invoker,HTTP端口尚未打开(它将无法打开直到所有应用程序都已启动)。所以A将开始,B将挂起,因为它正在寻找的端口尚未可用。卫生署。
最终结果是两个单独的Tomcat实例。
答案 0 :(得分:6)
如果您不关心破解一些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标记内以正确的顺序声明所有Web应用程序,它就可以解决问题:
<Host>
<context app1>
<context app2>
</Host>
Thaen app1将在app2之前启动,无论你使用哪个。
答案 1 :(得分:5)
我们遇到了同样的问题,为了解决这个问题,我们依赖的事实(我知道很滑)应用程序是按<tomcat_home>/conf/server.xml
中定义的顺序启动的。
这当然有一个缺点,即在server.xml
中对应用程序进行硬编码,但我们可以忍受它。
答案 2 :(得分:3)
旧线程,但是...
解决此问题的另一种方法是创建一个自定义HostConfig类,该类按所需方式对Web应用程序进行排序。
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 name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" hostConfigClass="your.package.OrderedHostConfig">
您需要将其编译到jar中并将其保存在Tomcat的/ lib目录中。就我而言:
/ var / lib / tomcat8 / lib
我喜欢这种方法是因为:
仅在相关的情况下强制执行该命令,但无需使用上下文在主机定义中手动管理所有webapps
在代码库中搜索.war文件名也将引用此类,这使得查找文件是否重命名更加容易。
tomcat 8的私有最终字段未更改,请参见here
答案 3 :(得分:2)
这是Linux上的另一个技巧。
由于错误的WSDL,我们的一些Web服务应用程序无法部署。如果在许多其他应用程序之后部署或启动它们,则会发生这种情况。 它们的启动顺序取决于在/ opt / apache-tomee / conf / Catalina / localhost
中找到上下文xml的顺序可以使用“ls -1f
”进行验证。普通的“ls”给出了一个排序的输出。
这曾经是文件添加到该目录的顺序,但是对于ext4文件系统,顺序基于文件名的哈希。可以按如下方式禁用它:
# tune2fs -O ^dir_index /dev/xyz
现在你至少可以决定自己将以何种顺序开始。重新排序:将所有文件移动到临时文件夹,按所需顺序将其移回。
答案 4 :(得分:1)
理论上,您可以在Runnable
中按ExecutorService
生成contextInitialized()
,HEAD
会在定时间隔检查其他网络应用的可用性(可能是通过触发HTTP Filter
请求?)。一旦其他webapp可用,然后在servlet上下文中设置一些指示该属性的属性。添加{{1}},检查是否存在该属性,并相应地阻止/继续请求。
答案 5 :(得分:1)
我知道这个问题有点陈旧,但我在尝试做同样的事情时发现它并认为我会用更好的解决方案进行更新...
您可以在server.xml中定义多个服务,这些服务在不同的端口上运行。服务按照它们在server.xml中出现的顺序依次启动。这意味着您可以 - 例如 - 在第一个服务中运行配置服务,然后在第二个服务中运行依赖它的应用程序(我使用其余的默认Catalina ...)
您可以在此处查看更多信息: http://wiki.apache.org/tomcat/FAQ/Miscellaneous#Q27
这是我在 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 ...
注意更改服务和引擎的名称非常重要。
HTH
答案 6 :(得分:0)
这是一个很好的技巧,我用来创建2级webapp加载。在每个级别,订单不能保证。这取决于tomcat将从tomcat / conf / [Engine Name] / [Host Name]加载第一个上下文描述符,然后才从server.xml中Host元素的appBase属性加载上下文
只需在想要在第二级加载的webapp中的某处(即稍后)添加以下代码
File contextDescriptor = new File(getParameter("catalina.home"),"/conf/Catalina/localhost/mywebapp.xml");
contextDescriptor.deleteOnExit();
答案 7 :(得分:0)
由于所有选项均不适用于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);
}
}
HostConfig 中的 deployApps 函数必须被覆盖才能进行排序以适用于所有内容(包括/ webapps文件夹中的WAR文件以及configbase文件夹中的描述符XML文件) (例如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);
}
}
然后,我们将新类放入Tomcat / lib目录中的新jar文件中,并修改conf / server.xml文件以用我们自己的实现替换主机类:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" className="com.example.CustomTomcatHost" >
在启动过程中,Tomcat按要求的顺序加载了所有组件。
答案 8 :(得分:0)
是否可以按照部署顺序从头开始?
因此,如果我有四个应用程序:1、2、3、4,并且我按以下顺序部署它们:1、2、4(重新启动tomcat),3(重新启动)。是否在某处缓存了一些内容,以使项目始终按该顺序启动?所以1、2、4、3。我不确定,但也许可以帮助某人。