我有三个战争在我的webapp文件夹。其中两个是建立在第三个的服务之上的。我在一个测试环境中,也就是说,我不能控制他们的架构,所以我不能改变任何事情。所以…
问题:有没有办法在tomcat中强制执行部署顺序?
我在stackoverflow中遇到了一个问题,但是没有解决方案。
嗯,实际上这家伙建议把web应用程序的名字按字母顺序改变会有帮助。但是,我不愿意每次我需要测试这些和不同的战争时都这样做。
我肯定有一种方法可以配置tomcat conf .xml文件之一。我只是不知道是哪一个。
来自Tomcat Wiki - webapps启动的顺序是什么(或者我如何更改启动顺序)?
没有预期的启动顺序。Servlet规范也没有Tomcat定义一个。你不能指望应用程序在任何地方启动特定顺序。
Tomcat有never支持指定webapps的加载顺序。还有其他容器(如JBoss)可以这样做,但是Tomcat没有。任何看起来像通过web应用程序名称的字母顺序加载排序的明显行为都是巧合,并不能保证在所有情况下都有效。
你可能想到的是<load-on-startup/>
元素,如果web.xml
指定了加载servlets
的顺序。
也就是说,有一个使用服务发现协议的优雅解决方案。
一个解决方案是使用像ZeroConf这样的东西,在服务启动时注册你的服务,然后让依赖的应用程序寻找这些服务何时可用,并在服务准备好时让它们连接并做它们需要做的事情。这就是我多年来处理多个依赖服务的方式。我有Python, Java和Erlang服务都可以通过ZeroConf无缝地发现彼此。
tomcat确实没有提供任何强制部署顺序的方法。
*Tomcat按照以下顺序部署webapps:*
1。任何上下文描述符将首先被部署。
2。未被任何上下文描述符引用的已分解的web应用程序将被部署。如果它们在appBase中有一个相关联的。war文件,并且它比被分解的web应用程序更新,那么被分解的目录将被删除,web应用程序将从。war
中重新部署。3。WAR文件将被部署
>这里是一个建议的解决方案:
如果你想指定部署顺序,那么在$CATALINA_BASE/conf/[engineename]/[hostname]/MyApp.xml中为你的web应用定义一个上下文
Tomcat扫描$CATALINA_BASE/conf/[engineename]/[hostname]/通过执行File listFiles()返回一个按哈希值排序的File数组(依赖于操作系统)。
你可以使用下面的代码来检查webapps的部署顺序
File file = new File("/opt/tomcat/conf/Catalina/localhost");
File[] files = file.listFiles();
for (File f : files)
{
System.out.println("Filename: " + f.getName());
}
为交叉发布道歉(Tomcat -以特定顺序启动webapps),但我认为这也是相关的:
您可以在server.xml中定义多个服务,它们运行在不同的端口上。服务按照它们在server.xml中出现的顺序依次启动。这意味着你可以——例如——在第一个服务中运行一个配置服务,然后在第二个服务中运行依赖于它的应用程序(我使用默认的Catalina…)
你可以在这里看到更多信息:http://wiki.apache.org/tomcat/FAQ/Miscellaneous问
这是我在之前包含的服务 正如你所看到的,我使用docbase而不是appBase,但是你应该能够配置一个不同的appBase,如果你喜欢… 注意,同时更改服务和引擎的名称是很重要的。 HTH <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>
有三种方法可以在Tomcat中部署webapp.war
。
-
在
$CATALINA_BASE/conf/server.xml
文件的Host
元素中添加Context
元素<Server><Service><Engine><Host> <Context path="[webappName]" docBase="[webappPath]"/> </Server></Service></Engine></Host>
-
创建
$CATALINA_BASE/conf/[engineName]/[hostName]/[webappName].xml
文件,内容为:<Context docBase="[webappPath]"/>
-
直接在
$CATALINA_BASE/webapps/
目录下添加webapp.war
文件
Tomcat启动时将执行以下部署顺序:
1→2→3
一些解释:
- CATALINA_BASE美元
引用解析大多数相对路径的基目录。如果您没有通过设置CATALINA_BASE目录来为多个实例配置Tomcat,那么$CATALINA_BASE将被设置为$CATALINA_HOME的值,即您已经安装Tomcat的目录。
docBase
web应用程序WAR文件的路径名。您可以为这个WAR文件指定一个绝对路径名,或者一个相对于所属主机的appBase目录的路径名。
engineName:
与上下文关联的引擎的名称。默认名称为
Catalina
主机名:
与上下文关联的主机名。默认名称为
localhost
假设:
- 有3个webapps:
a.war
,b.war
和c.war
。 -
b.war
依赖于a.war
-
c.war
依赖于b.war
- Server.Service.Engine.name = "Catalina"
- Server.Service.Engine.Host.name = "localhost"
- Server.Service.Engine.Host。appBase = "webapps"
尝试以下步骤:
- 把所有的war文件放到
$CATALINA_BASE/webapps/
目录下。 创建
$CATALINA_BASE/conf/Catalina/localhost/b.xml
文件,内容为:<Context docBase="b.war"/>
在
$CATALINA_BASE/conf/server.xml
文件中添加Context
元素:<Server><Service><Engine><Host> <Context path="a" docBase="a.war"/> </Server></Service></Engine></Host>
参考:
- https://tomcat.apache.org/tomcat - 9.0 - doc/deployer howto.html
- http://tomcat.apache.org/tomcat - 9.0 - doc/config/context.html
始终可以将第一个.war文件移动到tomcat目录中,然后等待它部署,然后将接下来的两个文件移动到tomcat目录中。这将部署第一个,然后部署其他两个。
或者,您可以使用Tomcat扫描目录并按字母顺序部署第一场战争,然后是第二场战争,然后是第三场战争
这很容易实现,如果您不在乎破解Tomcat代码并创建自己的主机实例
1)创建org.apache.catalina.core的子类。标准主机,输入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主机标签()
看起来不可思议,它解决了问题,只要你有所有的web应用程序声明在正确的顺序内的Host标签:
<Host>
<context app1>
<context app2>
那么,无论您使用哪种SO, app1都将在app2之前启动。
我们运行多个tomcat。我们可以通过将第一组应用程序放在一个tomcat中,后一组应用程序放在另一个tomcat中来独立地创建应用程序组。
这假设它们没有尝试使用JVM相互通信。
基于@Luiz对Tomcat 9的回答(其中children
现在是最终的),我们必须重写几个方法,在某些情况下复制基本功能。
这并没有优化任何东西,但它确实按照server.xml
中定义的顺序加载上下文。
// DeterministicDeployOrderHost.java
import java.lang.Override;
import java.lang.String;
import java.util.LinkedHashSet;
import javax.management.ObjectName;
import org.apache.catalina.Container;
public class DeterministicDeployOrderHost extends org.apache.catalina.core.StandardHost {
private final LinkedHashSet<String> childrenOrder = new LinkedHashSet<>();
@Override
public void addChild(Container container) {
synchronized (children) {
super.addChild(container);
childrenOrder.add(container.getName());
}
}
@Override
public void removeChild(Container container) {
synchronized (children) {
super.removeChild(container);
childrenOrder.remove(container.getName());
}
}
@Override
public Container[] findChildren() {
synchronized (children) {
var list = new java.util.ArrayList<Container>(children.size());
for (var childName : childrenOrder) {
list.add(children.get(childName));
}
return list.toArray(new Container[0]);
}
}
@Override
public ObjectName[] getChildren() {
var names = new java.util.ArrayList<ObjectName>(children.size());
for (var childName : childrenOrder) {
var next = children.get(childName);
if (next instanceof org.apache.catalina.core.ContainerBase) {
names.add(next.getObjectName());
}
}
return names.toArray(new ObjectName[0]);
}
}
从Maven仓库获取tomcat-catalina-*.jar,并将其编译为DeterministicDeployOrderHost.class
:
javac DeterministicDeployOrderHost.java -cp tomcat-catalina-9.0.65.jar
将编译后的.class
文件复制到$CATALINA_HOME/lib
中,并添加如下内容到主机:
<Host ... className="DeterministicDeployOrderHost">
<Context .../>
<Context .../>
</Host>