how to catch the event of shutting down of tomcat? - java

What I want is to start a thread every time the tomcat server starts.For this I need to catch the event of shutting down of tomcat.How can I do this?I tried to do it using sessions but sometimes the session even persists after shutting down and restating tomcat?what are my options?

You can try to catch an JVM shutdown event in this way:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("BYE BYE");
}
});
The other option is to implement ServletContextListener by using #WebListener Annotation. No xml configuration is required in this case.
#WebListener
public class MyLifeCycleListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
//TODO ON START
}
public void contextDestroyed(ServletContextEvent event) {
//TODO ON DESTROY
}
}

Related

Stop Spring Boot on thread error

I have this configuration using Spring Boot:
#Bean
public TaskExecutor a() {
return new SimpleAsyncTaskExecutor();
}
#Bean
public CommandLineRunner b() {
return (String... args) -> {
RunnableTask task = SomeRunnableTask();
a().execute(task);
};
}
When that thread stops (for any reason) I want to shut down the Spring Boot application.
The thread is a long running process connecting to a database, webservice, socket... So it's quite likely that at some point it'll fail.
What's the right way of shutting down Spring Boot when a thread stops? Should I not be using SimpleAsyncTaskExecutor from Spring?
Thanks!
Spring Boot has a ShutdownEndpoint which
Allows the application to be gracefully shutdown (not enabled by default).
You have to take a look on it:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500L); // For the response to be sent back to the requester
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
ShutdownEndpoint.this.context.close(); // The ConfigurableApplicationContext
}
});
thread.setContextClassLoader(getClass().getClassLoader());
thread.start();

Trigger a function upon Weblogic termination

Is there anyway to capture weblogic termination event and trigger a Java function?
My weblogic version is V10.0
Thank you,
You could imlement a javax.servlet.ServletContextListener
public class MyServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent e) {
}
public void contextDestroyed(ServletContextEvent e) {
}
}
and add it to the web.xml.
<listener>
<listener-class>MyServletContextListener</listener-class>
</listener>
There you can handle the shutdwn of the weblogic container.

How does Lifecycle interface work in Spring? What are "top-level singleton beans"?

It is said in Spring javadoc, that "Note that the Lifecycle interface is only supported on top-level singleton beans." Here URL
My LifecycleBeanTest.xml describes bean as follows:
<beans ...>
<bean id="lifecycle" class="tests.LifecycleBean"/>
</beans>
so it looks "topish" and "singletonish" enough.
What does it mean? How to make Spring know about my bean implementing Lifecycle and do something with it?
Suppose my main method looks following in Spring
public static void main(String[] args) {
new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").close();
}
so, it instantiates context and then closes it immediately.
May I create some bean in my configuration, which delays close() execution until application do all it's works? So that main method thread wait for application termination?
For example, the following bean does not work in way I thought. Neither start() not stop() is called.
package tests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;
public class LifecycleBean implements Lifecycle {
private static final Logger log = LoggerFactory.getLogger(LifecycleBean.class);
private final Thread thread = new Thread("Lifecycle") {
{
setDaemon(false);
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Abnormal thread termination", e);
}
});
}
public void run() {
for(int i=0; i<10 && !isInterrupted(); ++i) {
log.info("Hearbeat {}", i);
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
};
};
#Override
public void start() {
log.info("Starting bean");
thread.start();
}
#Override
public void stop() {
log.info("Stopping bean");
thread.interrupt();
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
#Override
public boolean isRunning() {
return thread.isAlive();
}
}
UPDATE 1
I know I can wait for bean in code. It is interesting to hook into Spring itself.
You should use SmartLifecycle instead of Lifecycle. Only the former is working as you expected Lifecycle to work. Make sure you return true in your isRunning() implementation.
I have used SmartLifecycle for asynchronous jobs for which it sounds like designed for. I suppose it will work for you but at the same time you may have a look at ApplicationListener and events like ContextStoppedEvent.
You can examine AbstractApplicationContext.doClose() method and see that no interruption of application context closing has been provided by the Spring developers
protected void doClose() {
boolean actuallyClose;
synchronized (this.activeMonitor) {
actuallyClose = this.active && !this.closed;
this.closed = true;
}
if (actuallyClose) {
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
try {
getLifecycleProcessor().onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
synchronized (this.activeMonitor) {
this.active = false;
}
}
}
So you can't prevent the application context from closing.
Testing the service with TestContext framework
If you are using Spring test context framework with JUnit, I think you can use it to test services that implement Lifecycle, I used the technique from one of the internal Spring tests
Slightly modified LifecycleBean(I've added waitForTermination() method):
public class LifecycleBean implements Lifecycle {
private static final Logger log = LoggerFactory
.getLogger(LifecycleBean.class);
private final Thread thread = new Thread("Lifecycle") {
{
setDaemon(false);
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Abnormal thread termination", e);
}
});
}
public void run() {
for (int i = 0; i < 10 && !isInterrupted(); ++i) {
log.info("Hearbeat {}", i);
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
};
};
#Override
public void start() {
log.info("Starting bean");
thread.start();
}
#Override
public void stop() {
log.info("Stopping bean");
thread.interrupt();
waitForTermination();
}
#Override
public boolean isRunning() {
return thread.isAlive();
}
public void waitForTermination() {
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:Test-context.xml")
public class LifecycleBeanTest {
#Autowired
LifecycleBean bean;
Lifecycle appContextLifeCycle;
#Autowired
public void setLifeCycle(ApplicationContext context){
this.appContextLifeCycle = (Lifecycle)context;
}
#Test
public void testLifeCycle(){
//"start" application context
appContextLifeCycle.start();
bean.waitForTermination();
}
}
Test-context.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="LifecycleBean"/>
</beans>
P.S. starting and stopping the context is not a thing you may want to do many times on the same application context, so you may need to put #DirtiesContextannotation on your test methods for the best results.
Answer to the new version of the question
DefaultLifecycleProcessor uses beanFactory.getBeanNamesForType(Lifecycle.class, false, false); to retrieve the list of the beans implementing Lifecycle
From getBeanNamesForType javadoc:
NOTE: This method introspects top-level beans only. It does
not check nested beans which might match the specified type
as well.
So this method does not list the inner beans (they were called nested when only xml configuration was available - they are declared as nested bean xml elements).
Consider the following example from the documentation
<bean id="outer" class="...">
<!-- Instead of using a reference to target, just use an inner bean -->
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name"><value>Tony</value></property>
<property name="age"><value>51</value></property>
</bean>
</property>
</bean>
Start() and Stop() are merely events that are propagated by the application context they are not connected with lifetime of the application context, for example you can implement a download manager with some service beans - when the user hits "pause" button, you will broadcast the "stop" event, then when the user hits "start" button, you can resume the processing by broadcasting the "start" event. Spring is usable here, because it dispatches events in the proper order.
I never used Lifecycle interface and I am not sure how it is suppose to work. But it looks like simply calling start() on context calls these callbacks:
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("...");
ctx.start();
However typically I use #PostConstruct/#PreDestroy annotations or implement InitializingBean or DisposableBean:
public class LifecycleBean implements InitializingBean, DisposableBean {
#Override
public void afterPropertiesSet() {
//...
}
#Override
public void destroy() {
//...
}
}
Notice I don't call close() on application context. Since you are creating non-daemon thread in LifecycleBean the JVM remains running even when main exits.
When you stop that thread JVM exists but does not close application context properly. Basically last non-daemon thread stops, causing the whole JVM to terminate. Here is a bit hacky workaround - when your background non-daemon thread is about to finish, close the application context explicitly:
public class LifecycleBean implements ApplicationContextAware /* ... */ {
private AbstractApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = (AbstractApplicationContext)applicationContext;
}
public void run() {
for(int i=0; i<10 && !isInterrupted(); ++i) {
log.info("Hearbeat {}", i);
try {
sleep(1000);
} catch (InterruptedException e) {
}
}
applicationContext.close();
}
}
So, finally I foundm that if I:
1) Define my bean as implements Lifecycle
2) Introduce a delay in stop() method like this
#Override
public void stop() {
log.info("Stopping bean");
//thread.interrupt();
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
3) And code context creation as follows:
new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").stop();
Then I get what I want:
context creation code does not exit until all stops of all Lifecycle beans executed. So, this code works in JUnit tests
What about using SmartLifecycle? Seems like it provides all necessary functionality.
There is method public void stop(Runnable contextStopping) {}.
And you can continue app context closing by executing passed in contextStopping in time you want.
In my environment all works fine even on J-UNIT, of course by running them with SpringJUnit4ClassRunner.

JNDI lookup in ServletContextListener.contextDestroyed

I'm using JBoss 7.1.1 and servlet-api 2.5.
I have to shutdown some objects which located in JNDI on application shutdown.
I'm using ServletContextListener for this purposes:
public class MyServletContextListener implements ServletContextListener {
...
#Override
public void contextDestroyed(ServletContextEvent sce) {
((TaskClient) new InitialContext().lookup("myName")).disconnect();
}
}
But I get exception:
Error looking up myName, service service
jboss.naming.context.java.myName is not started
If I try to lookup the object when application is running everything is fine.
Thank you for any help.
update
How I bind data to jndi:
public class MyJbpmServletContextListener implements ServletContextListener {
public static final String TASK_CLIENT_JNDI_NAME = "myJbpmTaskClient";
private Log logger = SLF4JLogFactory.getLog(getClass());
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
TaskClient tc = ...
// long initialization of TaskClient
InitialContext context = new InitialContext();
context.bind(TASK_CLIENT_JNDI_NAME, client);
} catch (NamingException exception) {
logger.error("Cannot bind task client", exception);
}
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
try {
((TaskClient) new InitialContext().lookup(TASK_CLIENT_JNDI_NAME)).disconnect();
} catch (NamingException exception) {
logger.error("Cannot obtain task client", exception);
}
}
}
The object is accessible on following path TASK_CLIENT_JNDI_NAME when application runs. But when contextDestroyed called I have NamingException.
I don't know how and when it's destroyed. I only sure that I'm not rebind or unbind it.
update2
I also tried to use jndi paths java:comp/myName, java:comp/env/myName, java:/myName, java:jboss/myName. Behavior is the same: it possible to lookup object when application runs and unable to do it when ServletContextListener.contextDestroyed method called.
Looks like a JBoss bug to me, I created AS7-5746

How to shutdown ThreadPoolExecutor in spring bean when tomcat is shutdown?

I create a threadpoolexecutor in a spring bean, so I need to shutdown this executor when tomcat is shutdown.
public class PersistBO implements InitializingBean {
private ThreadPoolExecutor executer;
public void shutdownExecutor() {
executer.shutdown();
}
#Override
public void afterPropertiesSet() throws Exception {
taskQueue = new LinkedBlockingQueue<Runnable>(queueLength);
executer = new ThreadPoolExecutor(minThread, maxThread, threadKeepAliveTime,
TimeUnit.SECONDS, taskQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
}
I have searched solution on google and get a result. That is to add a shutdownhook to java.lang.runtime. However, the java docs says java.lang.Runtime#shutdownHook is called when the last non-daemon thread exits. So it is a dead lock. Is there any solution to shutdown executor in spring bean?
I guess lifecycle of the executor should depend on lifecycle of your application, not Tomcat as a whole. You can stop your application while Tomcat is still running, therefore Runtime.shutdownHook() is not applicable.
Since you already use Spring and its InitializingBean for initialization, you can use DispasableBean to perform cleanup when application context is being closed:
public class PersistBO implements InitializingBean, DisposableBean {
public void destroy() {
shutdownExecutor();
}
...
}
Use the Runtime to add a shutdown hook. Here's a very good tutorial by Heinz Kabutz: http://www.roseindia.net/javatutorials/hooking%20_into_the_shutdown_call.shtml
You can implement your own javax.servlet.ServletContextListener to be notified when your application is being shutdown and shutdown the pool from the listener.
Use the #Predestroy annotation on your shutdown method on the bean. this will result in spring calling this method when context is shutting down
Check if there is some executor service has a thread running in background. you can shutdown an executor by calling executor.shutdownNow().
also see http://taranmeet.com/jvm-not-shutting-down-on-spring-context-close/
Here is how to start and stop a thread in Spring bean.
#PostConstruct
public void init() {
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("myspringbean-thread-%d").build();
executorService = Executors.newSingleThreadExecutor(factory);
executorService.execute(new Runnable() {
#Override
public void run() {
try {
// do something
System.out.println("thread started");
} catch (Exception e) {
logger.error("error: ", e);
}
}
});
executorService.shutdown();
}
#PreDestroy
public void beandestroy() {
if(executorService != null){
executorService.shutdownNow();
}
}

Categories