How to prevent spring context loading on exception in ServletContextListener? - spring

I boostrap spring context using ContextLoaderListener.
Before this in web.xml I have my custom listener which pefrorms some checks. If those checks fail i do not want Spring context to be started.
How can i prevent Spring context loading if i had an Exception in another listener?
I would put some attribute in ServletContext, but i do not know how it can affect on loading of spring ctx.
Here is the very similar question: Stop deployment when Exception occurs in ServletContextListener

Here is what i did to solve that:
In my listener where i perform some checks, if something wrong happens, i set attribute to servlet context
#Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("checkFailed", true);
}
Then i extended Spring's ContextLoaderListener and overrided contextInitialized like this:
#Override
public void contextInitialized(ServletContextEvent event) {
if (event.getServletContext().getAttribute("checkFailed") != null) {
return;
}
super.contextInitialized(event);
}

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.

init method in jersey jax-rs web service

I'm new with jax-rs and have build a web service with jersey and glassfish.
What I need is a method, which is called once the service is started. In this method I want to load a custom config file, set some properties, write a log, and so on ...
I tried to use the constructor of the servlet but the constructor is called every time a GET or POST method is called.
what options I have to realize that?
Please tell, if some dependencies are needed, give me an idea how to add it to the pom.xml (or else)
There are multiple ways to achieve it, depending on what you have available in your application:
Using ServletContextListener from the Servlet API
Once JAX-RS is built on the top of the Servlet API, the following piece of code will do the trick:
#WebListener
public class StartupListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
// Perform action during application's startup
}
#Override
public void contextDestroyed(ServletContextEvent event) {
// Perform action during application's shutdown
}
}
Using #ApplicationScoped and #Observes from CDI
When using JAX-RS with CDI, you can have the following:
#ApplicationScoped
public class StartupListener {
public void init(#Observes
#Initialized(ApplicationScoped.class) ServletContext context) {
// Perform action during application's startup
}
public void destroy(#Observes
#Destroyed(ApplicationScoped.class) ServletContext context) {
// Perform action during application's shutdown
}
}
In this approach, you must use #ApplicationScoped from the javax.enterprise.context package and not #ApplicationScoped from the javax.faces.bean package.
Using #Startup and #Singleton from EJB
When using JAX-RS with EJB, you can try:
#Startup
#Singleton
public class StartupListener {
#PostConstruct
public void init() {
// Perform action during application's startup
}
#PreDestroy
public void destroy() {
// Perform action during application's shutdown
}
}
If you are interested in reading a properties file, check this question. If you are using CDI and you are open to add Apache DeltaSpike dependencies to your project, considering having a look at this answer.

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.

In a spring bean is it possible to have a shutdown method which can use transactions?

In the destroy method of a spring bean I want to execute some queries to clean up some stuff in the database. Spring doesn't seem to allow this by any means I can find.
The error is always something like:
Invocation of destroy method failed on
bean with name 'someBean':
org.springframework.beans.factory.BeanCreationNotAllowedException:
Error creating bean with name
'transactionManager': Singleton bean
creation not allowed while the
singletons of this factory are in
destruction (Do not request a bean
from a BeanFactory in a destroy method
implementation!)
The following will tell spring to call shutdownDestroy after the bean is no longer needed. But, I get the above error when trying to use transactions.
<bean id="someId" name="someName" class="someClass"
destroy-method="shutdownDestroy"/>
The same is true when I enable common lifecycle annotations using:
<bean class="org.springframework. ... .CommonAnnotationBeanPostProcessor"/>
and then mark the method with #PreDestroy. That method can't use transactions either.
Is there any way to do this?
EDIT:
Thanks! I had the bean implement SmartLifecycle and adding the following and it works very nicely.
private boolean isRunning = false;
#Override
public boolean isAutoStartup() {return true;}
#Override
public boolean isRunning() {return isRunning;}
/** Run as early as possible so the shutdown method can still use transactions. */
#Override
public int getPhase() {return Integer.MIN_VALUE;}
#Override
public void start() {isRunning = true;}
#Override
public void stop(Runnable callback) {
shutdownDestroy();
isRunning = false;
callback.run();
}
#Override
public void stop() {
shutdownDestroy();
isRunning = false;
}
Interesting Question. I'd say you should be able to do it by letting your bean implement SmartLifeCycle.
That way, if your int getPhase(); method returns Integer.MAX_VALUE, it will be among the first to be called when the ApplicationContext finally shuts down.
Reference:
3.6.1.5 Startup and shutdown
callbacks
SmartLifeCycle javadocs
I come across this same issue. After check spring's source code, U can try to implements
public class SomeBean implements ApplicationListener<ContextClosedEvent> {
public void onApplicationEvent(ContextClosedEvent event) {
stopHook();
}
}
onApplicationEvent will be call before bean destory, you can check it on spring's org.springframework.context.support.AbstractApplicationContext#doClose method. I paste it below, so ContextEvent -> LifeCycle -> Bean destory.
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();

Correct usage subclassing a spring ContextLoader for testing

For the integration tests for my spring application with junit I am subclassing org.springframework.test.context.ContextLoader, because I want to use a already present XmlWebApplicationContext for wiring up my test class like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=MyContextLoader.class)
#Transactional
public class MyTest {
#Autowired
public AccountDao accountDao;
}
The implementation of my ContextLoader is as follows:
public class MyContextLoader implements ContextLoader {
#Override
public String[] processLocations(Class<?> clazz, String... locations) {
return locations;
}
#Override
public ApplicationContext loadContext(String... locations) throws Exception {
try {
// Start Embedded Tomcat
EmbeddedTomcat tomcat = new EmbeddedTomcat("mas", 8080);
tomcat.launch();
Context rootContext = tomcat.getRootContext();
ContextLoaderListener contextLoaderListener = (ContextLoaderListener) rootContext.getApplicationLifecycleListeners()[0];
XmlWebApplicationContext context = (XmlWebApplicationContext) contextLoaderListener.getContext();
GenericApplicationContext c = new GenericApplicationContext(context);
AnnotationConfigUtils.registerAnnotationConfigProcessors(c);
//context.refresh();
//context.registerShutdownHook();
return context;
}
catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
When putting a breakpoint in the loadContext(...) method I can call getBean(AccountDao.class) and everything works fine. However, it seems that my test class actually is not autowired. I debugged a little and stepped through the spring code and it seems that in the method AbstractAutowireCapableBeanFactory.populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) the PropertyValues are not set for my class Test.
Maybe, am I setting up the Annotation Processing wrong?
Information to the code: As you might guess and see, I am doing an integration test and therefore starting an embedded tomcat server in order to test my RESTful webservice. How getting the application context with a "hack" from an embedded tomcat is shown in my post here: Getting Access to Spring with Embedded Tomcat 6
I am looking forward to your replies.
Erik
I think the problem here is that you're creating a new GenericApplicationContext, which is not the one that Spring uses to autowire the test bean.

Resources