Springboot嵌入式Tomcat类加载器速度慢

cyb*_*ion 12 java spring tomcat jax-ws spring-boot

我在CentOS 7.2上构建了一个使用SpringBoot v1.3.6.RELEASE Tomcat 8.0.36 Java 1.8u101的Web应用程序

Web应用程序也是一个调用另一个Web应用程序的SOAP客户端.(JAX-WS RI 2.2.9)如果应用程序保持空闲状态15秒,则第一个Web服务调用将停止近2秒.似乎停顿发生在oacloader.WebappClassLoaderBase中.

闲置15秒后

16:02:36.165:委托父类加载器org.springframework.boot.loader.LaunchedURLClassLoader@45283ce2

16:02:36.170:搜索本地存储库

16:02:36.170:findResource(META-INF/services/javax.xml.soap.MetaFactory)

16:02:38.533: - >找不到资源,返回null

16:02:38.533: - >找不到资源,返回null

下一个请求没有空闲时间

16:07:09.981:委托父类装配器org.springframework.boot.loader.LaunchedURLClassLoader@45283ce2

16:07:09.984:搜索本地存储库

16:07:09.985:findResource(META-INF/services/javax.xml.soap.MetaFactory)

16:07:09.986: - >找不到资源,返回null

16:07:09.986: - >找不到资源,返回null

16:07:09.988:findResources(META-INF/services

oacloader.WebappClassLoaderBase生成的所有上述消息,它们显然是由来自JAX-WS RI的ClientSOAPHandlerTube.processRequest引起的.

你会注意到第一次调用需要2秒以上,但后续调用只需要几毫秒.我想知道是否有人经历过这种行为?

可能的解决方案:是否可以在springboot中更改tomcat使用的类加载器以使用ParallelWebappClassLoader

或者这可能是类加载器上的可重载标志的产物,但我没有看到如何在springboot中更改该标志.

当使用Jetty作为容器运行时,不会发生这种情况.

最终解决方案:(感谢Gergely Bacso)

    @Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {

        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
             if (container instanceof TomcatEmbeddedServletContainerFactory) {
                customizeTomcat((TomcatEmbeddedServletContainerFactory) container);
            }
        }
        private void customizeTomcat(TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory) {
            tomcatEmbeddedServletContainerFactory.addContextCustomizers(new TomcatContextCustomizer() {
                @Override
                public void customize(Context cntxt) {
                    cntxt.setReloadable(false);
                }
            });
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

Ger*_*cso 5

实际上,您的发现相当不错,并且您已经有90%回答了您的问题。这两个事实:

  1. “似乎停滞发生在oacloader.WebappClassLoaderBase中”
  2. “使用Jetty作为容器运行时,不会发生这种情况。”

表明这将是与Tomcat相关的问题,因为:

  1. o.a.c. 代表 org.apache.catalina
  2. 您的代码在另一个容器上运行良好。(码头)

您还观察到,此问题是在15秒钟的空闲时间后发生的。这完全符合Tomcat的默认checkInterval设置,即:

如果已将可重载设置为true,则检查修改的类和资源之间的秒数。默认值为15秒。

简而言之:当前您的reloadable标志为ON,并且Tomcat尝试重新加载您的类,这在开发过程中很方便,但是在任何其他情况下都是不可接受的。但是,关闭它的方法不是通过Spring-boot。

解决方案:
您需要找到您的context.xml / server.xml,您将在其中找到如下所示的Context定义:

<Context ... reloadable="true">
Run Code Online (Sandbox Code Playgroud)

删除reloadable标志,您已经解决了问题。该文件本身可以位于$ CATALINE_HOME / conf的$ CATALINA_BASE / conf中,但实际上,要查找是否要使用某些IDE为您管理Tomcat,这些位置可能有些棘手。

如果使用Spring-boot嵌入式Tomcat:

您可以用来操纵Tomcat设置的类是:EmbeddedServletContainerCustomizer

通过此操作,您可以添加TomcatContextCustomizeraddContextCustomizers),以便可以调用setReloadable上下文本身。

我没有看到任何原因使Spring-boot需要将此标志设置为true。