Spring ошибка завершения планировщика
При разработке планировщика SPRING в контейнере tomcat я всегда получаю этот logoutput при отказе сервера webapp или shutdown:
Apr 28, 2010 4:21:33 PM org.apache.catalina.core.StandardService stop
INFO: Stopping service Catalina
Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1] but has failed to stop it. This is very likely to create a memory leak.
Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-2] but has failed to stop it. This is very likely to create a memory leak.
Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] but has failed to stop it. This is very likely to create a memory leak.
Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4] but has failed to stop it. This is very likely to create a memory leak.
Apr 28, 2010 4:21:33 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-5] but has failed to stop it. This is very likely to create a memory leak.
.
.
.
SEVERE: A web application created a ThreadLocal with key of type [org.springframework.core.NamedThreadLocal] (value [Prototype beans currently in creation]) and a value of type [null] (value [null]) but failed to remove it when the web application was stopped. To prevent a memory leak, the ThreadLocal has been forcibly removed.
Apr 28, 2010 4:21:34 PM org.apache.coyote.http11.Http11Protocol destroy
INFO: Stopping Coyote HTTP/1.1 on http-8606
Как я могу это исправить?
Благодарим вас stevedbrown
Я добавляю этот слушатель к моему webapp
public class ShutDownHook implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent arg0) {
BeanFactory bf = (BeanFactory) ContextLoader.getCurrentWebApplicationContext();
if (bf instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext)bf).close();
}
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
}
}
и мой web.xml
<listener>
<listener-class>pkg.utility.spring.ShutDownHook</listener-class>
</listener>
но ошибка все еще существует.
spring config:
<bean id="run" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="concurrent" value="false" />
<property name="targetObject" ref="scheduler" />
<property name="targetMethod" value="task" />
</bean>
<bean id="cronTrg" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="run" />
<property name="cronExpression" value="0/5 * * * * ?" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" destroy-method="destroy">
<property name="triggers">
<list>
<ref bean="cronTrg" />
</list>
</property>
</bean>
Ответы
Ответ 1
Вам нужно добавить крюк выключения - см. Регистрация крюка выключения в Spring 2.5.
В вашем случае вам, вероятно, следует добавить прослушиватель контекста к вашему webapp, который делает это (запись в web.xml для слушателя + класс реализации).
Используйте close, это проще всего.
((YourClass)yourObject).close();
Ответ 2
Imho это проблема кварцевого планировщика. Я подал ошибку https://jira.terracotta.org/jira/browse/QTZ-192. В качестве обходного решения для меня работает сон(), предложенный Колином Петерсом.
Чтобы не запускать выключение дважды, вы также можете добавить сон к Spring SchedulerFactoryBean:
import org.quartz.SchedulerException;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
public class SchedulerFactoryBeanWithShutdownDelay extends SchedulerFactoryBean{
@Override
public void destroy() throws SchedulerException {
super.destroy();
// TODO: Ugly workaround for https://jira.terracotta.org/jira/browse/QTZ-192
try {
Thread.sleep( 1000 );
} catch( InterruptedException e ) {
throw new RuntimeException( e );
}
}
}
Ответ 3
Вот мое решение, так как никто из тех, кого я нашел в Интернете, не работал. Это специально для закрытия планировщика Quartz с Spring и Tomcat
Мое объяснение здесь: http://forum.springsource.org/showthread.php?34672-Quartz-doesn-t-shutdown&p=370060#post370060
В основном, по-видимому, проблема заключалась в том, что Quartz не хватает времени на чистое завершение работы, и аргумент waitForJobsToCompleteOnShutdown, похоже, не помогает. Поэтому я внедрил пользовательский прослушиватель выключения в webapp, получал ссылку на планировщик и закрывал его вручную. Затем подождите 1 секунду, прежде чем продолжить.
public class ShutDownHook implements ServletContextListener
{
@Override
public void contextDestroyed(ServletContextEvent arg0)
{
try
{
// Get a reference to the Scheduler and shut it down
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
Scheduler scheduler = (Scheduler) context.getBean("quartzSchedulerFactory");
scheduler.shutdown(true);
// Sleep for a bit so that we don't get any errors
Thread.sleep(1000);
}
catch (Exception e)
{
e.printStackTrace();
}
}
@Override
public void contextInitialized(ServletContextEvent arg0)
{
}
Ответ 4
Единственный способ гарантировать, что потоки завершены, состоит в том, чтобы прерывать и присоединяться к ним.
Это можно сделать, выполнив org.quartz.InterruptableJob
, как описано в ответе на вопрос Как предотвратить утечку памяти в кварце [?].