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

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.

Related

Spring - Instantiating beans results in infinite recursion and (ironic) StackOverflow exception. How to fix?

When I launch my application, for some reason not apparent to me it is waiting until it instantiates the SchedulerFactoryBean to instantiate the jtaTransactionManager bean. When it does this, Spring goes into an infinite recursion starting from resulting in a StackOverflow exception.
After tracing hte code, I see no circular dependency - transaction manager is not dependent in any way on the SchedulerAccessor
In the stack view image at the bottom, the Proxy$98 class is some enhancement of org.springframework.scheduling.quartz.SchedulerAccessor
Edit 1: Update
What is happening is that the SchedulerFactoryBean is being initialized in the preInstantiateSingletons() method of the bean factory. The transaction manager is not a singleton, so it is not pre-initialized. When Spring goes through the advisements, it tries to initialize the bean, but the advisement leads it back to the same pathway.
Edit 2: Internals (or infernals)
The spring class org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration implements the transactionManager attribute as a LazyProxy.
This is executed well before the initialization code constructs the actual TransactionManager bean. At some point, the class needs to invoke a transaction within the TransactionManager context, which causes the spring container to try to instantiate the bean. Since there is an advice on the bean proxy, the method interceptor in the SimpleBatchConfiguration class tries to execute the getTransaction() method, which in turn causes the spring container to try to instantiate the bean, which calls the intergceptor, which tries to execute the getTransaction() method ....
Edit 3: #EnableBatchProcessing
I use the word "apparent" a lot here because it's guesswork based on the failure modes during startup.
There is (apparently) no way to configure which transaction manager is being used in the #EnableBatchProcessing annotation. Stripping out the #EnableBatchProcessing has eliminated the recursive call, but left me with an apparent circular dependency.
For some unknown reason, even though I have traced and this code is called exactly once, it fails because it thinks the bean named "configurer" is already in creation:
#Bean({ "configurer", "defaultBatchConfigurer" })
#Order(1)
public BatchConfigurer configurer() throws IOException, SystemException {
DefaultBatchConfigurer result = new DefaultBatchConfigurer(securityDataSource(), transactionManager());
return result;
}
The code that initiates the recursion is:
protected void registerJobsAndTriggers() throws SchedulerException {
TransactionStatus transactionStatus = null;
if (this.transactionManager != null) {
transactionStatus = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
}
AppInitializer Startup Code:
#Override
public void onStartup(ServletContext container) throws ServletException {
Logger logger = LoggerFactory.getLogger(this.getClass());
try {
// DB2XADataSource db2DataSource = null;
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(DatabaseConfig.class);
rootContext.register(SecurityConfig.class);
rootContext.register(ExecutionContextConfig.class);
rootContext.register(SimpleBatchConfiguration.class);
rootContext.register(MailConfig.class);
rootContext.register(JmsConfig.class);
rootContext.register(SchedulerConfig.class);
rootContext.refresh();
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
Construction of jtaTransactionManager bean in DatabaseConfig
#Bean(destroyMethod = "shutdown")
#Order(1)
public BitronixTransactionManager bitronixTransactionManager() throws IOException, SystemException {
btmConfig();
BitronixTransactionManager bitronixTransactionManager = TransactionManagerServices.getTransactionManager();
bitronixTransactionManager.setTransactionTimeout(3600); // TODO: Make this configurable
return bitronixTransactionManager;
}
#Bean({ "transactionManager", "jtaTransactionManager" })
#Order(1)
public PlatformTransactionManager transactionManager() throws IOException, SystemException {
JtaTransactionManager mgr = new JtaTransactionManager();
mgr.setTransactionManager(bitronixTransactionManager());
mgr.setUserTransaction(bitronixTransactionManager());
mgr.setAllowCustomIsolationLevels(true);
mgr.setDefaultTimeout(3600);
mgr.afterPropertiesSet();
return mgr;
}
Construction of SchedulerFactoryBean in SchedulerConfig
#Autowired
#Qualifier("transactionManager")
public void setJtaTransactionManager(PlatformTransactionManager jtaTransactionManager) {
this.jtaTransactionManager = jtaTransactionManager;
}
#Bean
#Order(3)
public SchedulerFactoryBean schedulerFactoryBean() {
Properties quartzProperties = new Properties();
quartzProperties.put("org.quartz.jobStore.driverDelegateClass",
delegateClass.get(getDatabaseType()));
quartzProperties.put("org.quartz.jobStore.tablePrefix", getTableSchema()
+ ".QRTZ_");
quartzProperties.put("org.quartz.jobStore.class",
org.quartz.impl.jdbcjobstore.JobStoreCMT.class.getName());
quartzProperties.put("org.quartz.scheduler.instanceName",
"MxArchiveScheduler");
quartzProperties.put("org.quartz.threadPool.threadCount", "3");
SchedulerFactoryBean result = new SchedulerFactoryBean();
result.setDataSource(securityDataSource());
result.setNonTransactionalDataSource(nonJTAsecurityDataSource());
result.setTransactionManager(jtaTransactionManager);
result.setQuartzProperties(quartzProperties);
return result;
}
There were several impossibly convoluted to figure out steps to a resolution. I ended up monkeying it until it worked because the exception messages were not information.
In the end, here is the result:
refactored packaging so job/step scoped and global scoped beans were in different packages, so context scan could capture the right beans in the right context easily.
Cloned and modified org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration to acquire the beans I wanted for my application
Took out the #EnableBatchProcessing annotation. Since I was already initializing less automagically, everything was initializing twice which created confusion
Cleaned up the usage of datasources - XA and non-XA
Use the #Primary annotation to pick out the correct (Biting tongue here - no way to tell the framework which of several datasources to use without implicitly telling it that in case of questions always use "this one"? Really???)

Closing ApplicationContext

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
}
});

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.

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();

EasyMock object for unit testing involving scope="request" bean

I am trying to add some Unit Testing to some of our companies code. Yes, I know it should already be there, but not everyone seems to have the same view of unit testing that I do.
However, I have come against a bit of a stopper for me. Admittedly, my Java, Spring and Unit Testing knowledge are not all that they should be. My problem is this though:
I have added a unit test to my code, which tests a class. This class includes a bean which has scope="request", and when it tries to instantiate the bean it throws an exception:
java.lang.IllegalStateException: No Scope registered for scope 'request'
I believe this is because I don't have a HttpServletRequest object, but I don't know how to create a mock one of these and also I don't know how, once created, to add this Mock Object to the unit test so that it resolves this problem.
Below is a cut down version of the code involved, which I believe includes all of the details that are part of this problem.
How can I get this to work?
#Test
public void handleRequest() {
try {
Message<?> outMessage = (Message<?>) response.handleRequest(map);
} catch (Exception e) {
assertNotNull(e);
}
outMessage.getPayload().toString());
}
public class upddResponse extends AbstractResponseTransform {
#SuppressWarnings("unchecked")
public Message<?> handleRequest(Map<String, Message<?>> messages) throws Exception {
super.addEnvironmentDetails(serviceResponseDocument.getServiceResponse());
}
public abstract class AbstractResponseTransform implements ResponseTransform,
ApplicationContextAware {
private ApplicationContext applicationContext;
private MCSResponseAggregator mcsResponseAggregator;
public ServiceResponseType addEnvironmentDetails(ServiceResponseType serviceResponse) throws Exception {
try {
mcsResponseAggregator = (MCSResponseAggregator) applicationContext
.getBean("mcsResponseAggregator");
}
catch (Exception ex) {
}
}
}
public interface ResponseTransform extends Transform {
public Message<?> handleRequest(Map<String, Message<?>> messages)
throws Exception;
}
<bean id="mcsResponseAggregator" class="com.company.aggregator.MCSResponseAggregator" scope="request" />
You need a WebApplicationContext to handle beans with: scope="request"
I recommend to use stub objects with Spring integration tests and use EasyMock without Spring when you test a class isolated.
You can use mocks within the Spring Context:
but that will not solve your problem as it will not make Spring understand scope="request". You can create your own implementation of the request scope, but I'm getting the feeling that you're better off not going through all this trouble.
The easy way out would be to override your request scoped bean in a little test context. You're technically not testing the original context then, but you will be done a lot quicker.
Spring 3.2 comes with support for this. See "Spring MVC Test Framework"

Resources