2016-08-30 4 views
9

Я построил веб-приложение, которое использует SpringBoot v1.3.6.RELEASE Tomcat 8.0.36 Java 1.8u101 на CentOS 7.2Springboot встроенный Tomcat Загрузчик классов медленность

Веб-приложение является также SOAP-клиент, который вызывает (JAX-WS RI 2.2.9) Если приложения остаются бездействующими в течение 15 секунд, первый вызов webservice останавливается почти на 2 секунды. Похоже, что срыв происходит в o.a.c.loader.WebappClassLoaderBase.

После 15 секунд простоя

16: 02: 36,165: Делегирование к родительскому загрузчику [email protected]

16: 02: 36,170: Поиск локальных хранилищ

16: 02: 36,170: FindResource (META-INF/услуги/javax.xml.soap.MetaFactory)

16: 02: 38,533: -> Ресурс не найдено, возвращается нуль

16: 02: 38,533: -> Ресурс не найден, возвращая NULL

следующий запрос не время простоя

16: 07: 09.981: Делегирование к родительскому загрузчику org.springframework. [email protected]

16: 07: 09,984: Поиск локальных хранилищ

16: 07: 09.985: FindResource (META-INF/услуги/javax.xml.soap. MetaFactory)

16: 07: 09,986: -> Ресурс не найдено, возвращается нуль

16: 07: 09,986: -> Ресурс не найдено, возвращается нуль

16: 07: 09,988: findResources (META-INF/услуги

Все вышеуказанные сообщения, полученные oacloader.WebappClassLoaderBase, и они, по-видимому, вызвана ClientSOAPHandlerTube.processRequest, которая из JAX-WS RI.

Вы заметите, что первый вызов занимает более 2 секунд, но последующие вызовы занимают всего миллисекунды. Мне интересно, если кто-то испытал такое поведение?

Возможных решения: Можно ли изменить из загрузчиков классов, используемых котом в springboot использовать 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

Похоже, что кэш-память становится недействительной на 15 секунд бездействия, поэтому вызов 'findResource' должен снова искать весь путь к классам. Я не могу сказать, где этот кеш может быть, так как неясно, что генерирует вывод, который вы разделили выше.Полный пример, который воспроизводит проблему, поможет здесь. Я также посмотрю, что ищет ресурс 'META-INF/services/javax.xml.soap.MetaFactory'. Выполнение этого поиска для каждого запроса кажется ненужным, так как результат вряд ли изменился. –

+0

@ AndyWilkinson да, это мои мысли точно. Я посмотрел на WebappClassLoaderBase, и я не вижу кеша. Также я согласен с вами в том, что поиск каждого запроса кажется расточительным. Может быть, я попробую CXF вместо Metro и посмотреть, произойдет ли то же самое. – cyberoblivion

ответ

2

На самом деле ваши результаты довольно хорошо и у вас есть 90% ответили уже на ваш вопрос. Эти два факта:

  1. «оказывается, что срыв происходит в o.a.c.loader.WebappClassLoaderBase»
  2. «при запуске с использованием Jetty в качестве контейнера этого не происходит.»

показывают, что он собирается быть Tomcat, связанных с проблемой, потому что:

  1. o.a.c. стенды для org.apache.catalina
  2. Ваш код хорошо работает на другом контейнере. (Jetty)

Вы также заметили, что проблема происходит через 15 секунд бездействия. Это вполне соответствует настройке Tomcat по умолчанию checkInterval, что:

Количество секунд между проверками для модифицированных классов и ресурсов, если пополняемый было установлено верно. Значение по умолчанию: 15 секунд.

Короче говоря: в настоящее время ваш reloadable флаг включен, и Tomcat пытается перезагрузить ваши классы, которые удобно в процессе разработки, но неприемлемо в любом другом случае. Однако способ отключить это не через Spring-boot.

РЕШЕНИЕ:
Вы должны найти свой context.xml/server.xml, где вы найдете ваш Context определяется следующим образом:

<Context ... reloadable="true"> 

Снимите reloadable флаг, и вы решили проблему , Сам файл может быть либо в $ CATALINA_BASE/conf $ CATALINE_HOME/conf, но на самом деле эти места могут быть немного сложными, если вы используете некоторую среду IDE для управления Tomcat для вас.

В случае встроенного Tomcat с Спринг-ботинке:

класс можно использовать для manipulate Tomcat settings является: EmbeddedServletContainerCustomizer.

С помощью этого вы можете добавить TomcatContextCustomizer (addContextCustomizers), чтобы вы могли позвонить setReloadable по самому контексту.

Я не вижу никаких оснований для весенней загрузки, требующей этого флага в true.

+0

Этот флаг должен быть установлен в true по умолчанию в встроенном tomcat от springboot. В приложении springboot tomcat встроен в файл приложения jar, и, насколько я могу судить, он не использует файл context.xml. Я буду продолжать копаться в том, как можно изменить этот флаг в приложении springboot – cyberoblivion

+0

@cyberoblivion, я вижу проблему. Я расширил ответ. –

+0

Basco, я обновил вопрос с помощью решения, которое я придумал, основываясь на ваших отзывах! Благодарю. – cyberoblivion