Tomcat-按特定顺序启动Web应用程序

Tomcat-按特定顺序启动Web应用程序,tomcat,servlets,Tomcat,Servlets,我知道Tomcat和Servlet规范 然而,在我看来,这似乎是一个常见的用例,我想知道是否有人发现了一个聪明的解决方法 我有一个webappa,它使用springremoting来公开一个共享服务,webappb是其中的一个客户端。除非Webapp A正在运行,否则Webapp B无法初始化。然而,我的Tomcat总是以线性方式启动webapp,从webapp B开始 出于基础设施方面的原因,我必须让它们在同一个Tomcat服务器上运行 有什么想法吗 谢谢, 罗伊 更新- 事实证明,在我的特殊

我知道Tomcat和Servlet规范

然而,在我看来,这似乎是一个常见的用例,我想知道是否有人发现了一个聪明的解决方法

我有一个webappa,它使用springremoting来公开一个共享服务,webappb是其中的一个客户端。除非Webapp A正在运行,否则Webapp B无法初始化。然而,我的Tomcat总是以线性方式启动webapp,从webapp B开始

出于基础设施方面的原因,我必须让它们在同一个Tomcat服务器上运行

有什么想法吗

谢谢, 罗伊

更新-

事实证明,在我的特殊情况下,顺序并不重要。原因是:假设我使用以下方法之一在应用程序B之前启动应用程序A。因此应用程序A启动,但是,由于SpringRemoting使用HTTP调用程序,HTTP端口尚未打开(在所有应用程序启动之前它不会打开)。所以A将启动,B将挂起,因为它正在寻找的端口还不可用。Doh


最终的结果是两个独立的Tomcat实例。

我们有同样的问题,要解决这个问题,我们依赖于这样一个事实(我知道很滑),即应用程序是按照
/conf/server.xml
中定义的顺序启动的


这当然有一个缺点,那就是在
server.xml
中对应用程序进行硬编码,但我们可以接受它。

理论上,您可以通过
contextInitialized()
中的
ExecutorService
生成一个
Runnable
,然后每隔一定时间检查另一个webapp的可用性(可能通过触发HTTP
HEAD
请求?)。一旦另一个Web应用可用,然后在servlet上下文中设置一些属性,这表明。添加一个
过滤器
,检查该属性的存在,并相应地阻止/继续请求。

我使用了一个很好的技巧来创建两个级别的Web应用加载。在每个级别中,顺序都不保证。这依赖于tomcat将首先从tomcat/conf/[Engine Name]/[Host Name]加载上下文描述符,然后才从server.xml中Host元素的appBase属性加载上下文

只需将以下代码添加到您希望在第二级(即稍后)加载的webapp中


如果你不在乎破解一点tomcat代码和创建你自己的主机实例,这是很容易实现的

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主机标记()上注册类

尽管看起来不可思议,但只要您在主机标签中以正确的顺序声明所有web应用,它就能解决问题:

    <Host>
     <context app1>
     <context app2>
   </Host>


Thaen app1将在app2之前启动,无论您使用哪种方式

我知道这个问题有点老了,但我在尝试做同样的事情时发现了它,并认为我应该更新一个更好的解决方案

您可以在server.xml中定义在不同端口上运行的多个服务。这些服务按照它们在server.xml中的显示顺序依次启动。这意味着您可以在第一个服务中运行一个配置服务,然后在第二个服务中运行依赖它的应用程序(我使用默认的Catalina服务用于其余服务…)

您可以在此处查看更多信息:

这是我在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

这里是Linux上的另一个技巧

由于错误的WSDL,我们的一些webservice应用程序无法部署。如果在许多其他应用程序之后部署或启动它们,就会发生这种情况。 它们的启动顺序取决于在/opt/apache-tomee/conf/Catalina/localhost中找到上下文xml的顺序

可以使用“
ls-1f
”进行验证。一个普通的“ls”给出一个排序的输出

这过去是文件添加到该目录的顺序,但对于ext4文件系统,该顺序基于文件名的散列。可以按如下方式禁用此功能:

# tune2fs -O ^dir_index /dev/xyz
现在你至少可以自己决定它们的启动顺序。重新排序:将所有文件移到临时文件夹,按所需顺序将其移回。

旧线程,但

解决此问题的另一种方法是创建一个自定义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 
        };
    }
}
公共类OrderedHostConfig扩展了HostConfig{ @凌驾 受保护的字符串[]筛选器应用路径(字符串[]未筛选的应用路径){ String[]files=super.filterapppath(未筛选的应用路径); sort(文件,compare()); 归还文件; } 专用比较器compare(){ 返回(o1,o2)->{ //您自己的实现 }; } }
然后可以在主机定义下的server.xml中引用此类

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" hostConfigClass="your.package.OrderedHostConfig">

您需要将其编译成jar并保存在Tomcat的/lib目录中。就我而言:

/var/lib/tomcat8/lib

我喜欢这种方法,因为:

  • 该命令仅在相关的地方强制执行,但不需要使用上下文在主机定义中手动管理所有WebApp

  • 在代码库中搜索.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);
        }
    }
    
    必须覆盖HostConfig中的deployApps函数,以便进行排序
    public class CustomTomcatHost extends StandardHost {
    
        public CustomTomcatHost() {
            super();
        }
    
        @Override
        public void addLifecycleListener(LifecycleListener listener) {
            if (listener instanceof HostConfig) {
                listener = new OrderedHostConfig();
            }
            super.addLifecycleListener(listener);
        }
    }
    
    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);
        }
    }
    
    <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true" className="com.example.CustomTomcatHost" >