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

时间:2016-08-30 17:58:59

标签: java spring tomcat spring-boot jax-ws

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

Web应用程序也是一个调用另一个Web应用程序的SOAP客户端。(JAX-WS RI 2.2.9)如果应用程序保持空闲状态15秒,则第一个Web服务调用将停止近2秒。似乎停顿发生在o.a.c.loader.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

o.a.c.loader.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);
                }
            });
        }
    };
}

1 个答案:

答案 0 :(得分:4)

实际上你的发现非常好,你已经有90%回答了你的问题。这两个事实:

  1. “似乎停止发生在o.a.c.loader.WebappClassLoaderBase”
  2. “当使用Jetty作为容器运行时,这不会发生。”
  3. 显示它与Tomcat相关的问题是因为:

    1. o.a.c.代表org.apache.catalina
    2. 您的代码适用于其他容器。 (码头)
    3. 您还观察到,问题发生在15秒的空闲时间之后。这完全对应于Tomcat的默认checkInterval设置,即:

        

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

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

      <强>解:
      您需要找到您的context.xml / server.xml,您将在其中找到Context定义如下:

      <Context ... reloadable="true">
      

      删除reloadable标志,您已解决问题。文件本身可以在$ CATALINE_BH / conf $ CATALINE_HOME / conf中,但实际上,如果您使用某些IDE来管理Tomcat,这些位置可能会有点棘手。

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

      您可以使用manipulate Tomcat settings的课程为:EmbeddedServletContainerCustomizer

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

      我认为没有任何理由让Spring-boot需要这个标志为true。