Closing ApplicationContext - spring

I am using Spring 4.3. I am using ConfigurableApplicationContext and calling close() on it. As expected method annotated with #PreDestroy is called.
But I have seen that even if I don't call close then also #PreDestroy methods are called. I was under the impression that there is a chance of memory leak if close() is not called. Am I wrong?
Also, if I am using web application , what is the correct way to close the applicationcontext, regsiterShutdownHook?

Either you can register shutdown hook :
ConfigurableApplicationContext context = SpringApplication.run(Test.class, args);
context.registerShutdownHook();
or add a listener to do something :
ConfigurableApplicationContext context = SpringApplication.run(Test.class, args);
context.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
#Override
public void onApplicationEvent(ContextClosedEvent event) {
// some logic
}
});

Related

Is #PreDestroy method call granted if we get an Exception in #PostConstract

I have SpringBoot application which is load some configuration and runs a longtime processing in method annotated with #PostConstract. There are some resources which should be released if application completed successfully or with an Error.
The question is how to make the most correct release of application resources? Is that enough to make it in #PreDestroy annotated method or I should also catch the exception in #PostConstract annotated method.
#SpringBootApplication
#Import(MyConfiguration.class)
public class MySpringApplication {
#Autowire
ProcessRunner processRunner;
#Autowire
ResourceBean resourceBean;
public static void main(String[] args) {
SpringApplication.run(MySpringApplication.class, args);
}
#PostConstruct
void postConstruct {
try {
processRunner.run()
} catch (Exception ex) {
// Do we really need this Exception handling to release resource?
resourceBean.release();
}
}
#PreDestroy
void preDestroy() {
resourceBean.release();
}
}
PreDestroy
Works as callback when the context releases a bean (i.e: on context close). This means that PreDestroy is not coupled with PostConstruct. If the bean exists in the context and it is released, predestroy will be called.
PostConstruct
Meant to initialize beans. If it throws an exception the Application will not start.
So, answering your question...
is predestroy-method-call granted if we get an exception in postconstract?
PreDestroy and PostConstruct are not coupled. This means, if PostConstruct got an exception but was managed somehow and the method ended successfully, the bean will be initialized and it will be available in the context. When the time comes and the context is closed, the bean will be released and PreDestroy will be called.
If PostConstruct THROWS an exception, the Bean won't be available at the context (and the app won't start), hence PreDestroy won't be called.
The question is how to make the most correct release of application resources? Is that enough to make it in #PreDestroy annotated method or I should also catch the exception in #PostConstract annotated method?
You should catch the exception and release any unmanaged resource. This also applies to JEE which specifies that as best practice, resources acquired outside of the context must be handled programmatically.
The #PostConstruct and #PreDestroy annotations allow you to define lifecycle callbacks for your beans (see the documentation for details).
If the #PostConstruct annotated method may throw exceptions, you should catch them and handle the release of the resources accordingly. Consider the following example:
#SpringBootApplication
public class MySpringApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringApplication.class, args);
}
#PostConstruct
public void init() {
System.out.println("#PostConstruct method executed");
throw new RuntimeException();
}
#PreDestroy
public void destroy() {
System.out.println("#PreDestroy method executed");
}
}
In this situation, the #PreDestroy annotated method won't be executed.

Catch application stop event for Spring-boot application

Is there a clean way to detect when a spring-boot application is stopped and perform some action before? Kind of CommandLineRunner for stopping a service
Thanks in advance
Similar to ApplicationReadyEvent you can use ContextClosedEvent:
#Component
public class ContextClosedEventListener {
#EventListener(ContextClosedEvent.class)
public void onContextClosedEvent(ContextClosedEvent contextClosedEvent) {
System.out.println("ContextClosedEvent occurred at millis: " + contextClosedEvent.getTimestamp());
}
}
I've come up with this solution. If you have better one, feel free to share
#Component
public class PortalServiceLifeCycle implements CommandLineRunner {
static final Logger LOGGER = LoggerFactory.getLogger(PortalServiceLifeCycle.class);
#Override
public void run(String... arg0) throws Exception {
LOGGER.info("###START FROM THE LIFECYCLE###");
}
#PreDestroy
public void onExit() {
LOGGER.info("###STOP FROM THE LIFECYCLE###");
}
}
Don't know if you have resolve this problem perfectly. I meet this issue recently, and have got a solution that a little different.
Firstly, my Spring boot Application is a Tomcat embedded one. (The second method of this issue doesn't depends on the web structure. don't mad, my friend.) In this case, it's naturally to get the idea of catch the stop event by register a listener. I do it like this,
#WebListener
public class HelloListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextInitialized");
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextDestroyed");
}
}
and, at the same time, add the annotation #ServletComponentScan on your Application class.
Surely, there are some other ways to register a ServletContextListener, and once you registered it, you can get the stop event in the contextDestroyed function.
BUT, that don't match my issue very much. I must catch the stop event BEFORE the Spring Beans being destroyed. And here comes the second solution.
modify your application main method like the follow:
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addListeners(new MyListener());
application.run(args);
and provide the defination of class MyListener:
class MyListener implements ApplicationListener<ContextClosedEvent>{
#Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
// your code here
}
}
NOTE: the second solution has nothing to do with Tomcat or other web container. The ContextClosedEvent isn't introduced in the Spring document, but I found it in the source, it's very useful i think.
I will be very glad if this can help some one.
It depends what you want to do but one thing you could do is have a bean that implements SmartLifecycle and implement the stop method. Whenever the context is being stopped, you'd get a callback. Note that it does not necessarily means that the process is shutting down. If you want to invoke some code when that happens, I'd register a shutdown hook as Sven wrote in a comment.

Spring boot acitvemq keep receiver running periodically

I have configured a spring boot application which when run reads messages from the queue and processes them accordingly.
I also have configured the concurrency flag to run multiple such readers.
However in an ideal world i would like the receiver to keep running like a thread and keep checking for any messages.
My question is that whether there is any way i can configure this in spring boot or i have to fallback to using threading mechanism using executor or anything else.
Thanks,
- Vaibhav
I found a nice way from Spring Boot, the concurrency was of course taken case by concurrent attribute e.g.
#JmsListener(destination = "myqueue", concurrency="2-10")
However for the Thread part below was something which is a neat way:
#SpringBootApplication
#EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
#EnableJms
public class MyApplication implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Override
public void run(String... arg0) throws Exception {
// TODO Auto-generated method stub
System.out.println("Joining Thread ctrl+c to bring down application");
Thread.currentThread().join();
}
}

How to participate in the Spring Applicaiton Context Initialization Lifecycle?

How do I hook into the initialization of the Spring Application Context, in a way that allows my code to halt the initialization?
I want to write code which executes after all the beans are fully initialized but before Spring fires ContextRefreshedEvent with the ability to halt the initialization if my code fails to do what it needs to do.
In particular I want to start Quartz Schedule but only after everything has started and if quartz fails to start I want to stop the application. Currently I am using a Servlet context listener like this one to accomplish the task.
public class QuartzServletContextListener implements ServletContextListener
{
#Override
public void contextInitialized(ServletContextEvent sce)
{
ServletContext servletContext = sce.getServletContext();
WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
Scheduler scheduler = applicationContext.getBean(Scheduler.class);
try
{
scheduler.start();
} catch (SchedulerException e)
{
throw new RuntimeException(e);
}
}
#Override
public void contextDestroyed(ServletContextEvent sce)
{
}
}
The servlet context listener runs after the spring context loader listener and the RuntimeException stops tomcat.

Accessing Spring context from non-spring component that is loaded at the same time with Spring

The cool enterprise app I'm working on is in the process of going Spring. That's very cool and exciting exercise to all the team, but also a huge source of stress. What we do is we gradually move legacy components to Spring context. Now what we have is a huuuge, I mean it, huuuuge component that is not piece of cake to spring-ify, and at the same time it needs to get access to some of the Spring beans.
Now here comes the problem: this component is being loaded at application startup (or bootstrap, whatever you prefer!). That means that there is a race condition between this guy and a Spring itself, so sometimes when I access the context from within that non-spring monstrosity, I get sweet and nice NPE. Which basically means that at the time we need that context, it's not yet initialized!
You might be curious how exactly we're accessing the context: and the answer is - it's a standard AppContextProvider pattern.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx;
public void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
The ideal workaround for me in this case would be to tell Spring to notify that non-spring component "Okay, I'm up!", and perform all actions that require the context only after that. Is this actually possible?
Thanks in advance!
The correct way to make the application context available to non-spring beans is to use the ContextSingletonBeanFactoryLocator.
Take a look at this answer for more details.
Take a look at the mechanism of context events.
Perhaps you can block getApplicationConext() until receiving of ContextRefreshedEvent (if it wouldn't create deadlocks):
public class ApplicationContextProvider implements ApplicationListener<ContextRefreshedEvent> {
private static ApplicationContext ctx;
private static Object lock = new Object();
public void onApplicationEvent(ContextRefreshedEvent e) {
synchronized (lock) {
ctx = e.getApplicationContext();
lock.notifyAll();
}
}
public static ApplicationContext getApplicationContext() {
synchronized (lock) {
while (ctx == null) lock.wait();
return ctx;
}
}
}

Resources