Why in destroy method is not called automatically in below when object will destroy? - spring

public class Instrumentalist implements Performer, InitializingBean, DisposableBean {
private Instrument instrument;
private String song;
public void setInstrument(Instrument instrument)
{
this.instrument=instrument;
}
public void setSong(String song)
{
this.song=song;
}
public void afterPropertiesSet() throws Exception
{
System.out.println("Before Playing Instrument");
}
public void destroy() throws Exception
{
System.out.println("After Playing Instrument");
}
public void perform() {
// TODO Auto-generated method stub
System.out.println("Playing "+ song + " : ");
instrument.play();
}
}
In above example only i got the out put in which afterPropertiesSet() is called but not destroy method. Below is my config.xml
<bean id="dhiraj" class="Instrumentalist">
<property name="song" value="Sa Re Ga Ma" />
<property name="instrument" ref="piano" />
</bean>
<bean id="piano" class="Piano" />
and i called from my main method as below -
ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
Performer performer1=(Performer)context.getBean("dhiraj");
performer1.perform();

Try this:
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
//...
context.close(); //!!!
You have to close the context manually, otherwise Spring does not know that the bean is no longer needed and should be destroyed. Note that you have to use AbstractApplicationContext type as ApplicationContext interface does not define close().

For singleton beans like dhiraj, the destroy() lifecycle method will be called when, and only when, the application context is shut down.
If your code fragment is the entirety of your program, then destroy() will not be called because you're not closing the context properly.
Add context.close() to the end of your fragment, and you'll see destroy() being called.

You need to close Context Object,Then Only destroy method is called.Check for img
ConfigurableApplicationContext Context= new ClassPathXmlApplicationContext("ApplicationContext.xml");
//.............
//.........
Context.close();
**

You can also register shutdown hook this way:
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
context.registerShutdownHook();

Related

Spring ExitCodeEvent using #EventListener not working

I am trying to catch the event code at the time my springboot app is destroyed. I have the following bean:
#Configuration
public class DestroyListenerConfig {
#Bean
DemoListener demoListenerBean() {
return new DemoListener();
}
private static class DemoListener {
#EventListener
public void exitEvent(ExitCodeEvent event) {
System.out.println("Exit code: " + event.getExitCode());
}
}
}
The bean is registering properly, but when I kill the application, the exitEvent() method is not invoked ( the system out never displays, or when run in debug mode from IDE, it never enters the method).
Am I leaving something out? My impression was this is all that is needed. Thanks.
ExitCodeEvent is published from org.springframework.boot.SpringApplication#exit. So, you need to manually call SpringApplication.exit as below.
#Autowired
ApplicationContext applicationContext;
#GetMapping("/shutdown")
void shutdown() {
SpringApplication.exit(applicationContext, () -> 100);
}
If you want to listen to a bean destroy event then you can use #PreDestroy as following:
Note that if you have multiple beans created for this class, you will get multiple triggers.
//Put this into a #Component(or inside RestController, Controller, Service etc) class
#javax.annotation.PreDestroy
public void destroy() {
System.out.println("Triggered - #PreDestroy.");
}
If your app is a webapp and you want to listen to shutdown event (ideally the contextDestroyed event) you can register a MyServletContextListener to ServletListenerRegistrationBean:
#Bean
ServletListenerRegistrationBean<ServletContextListener> servletListener() {
ServletListenerRegistrationBean<ServletContextListener> srb = new ServletListenerRegistrationBean<>();
srb.setListener(new MyServletContextListener());
return srb;
}
class MyServletContextListener implements ServletContextListener {
#Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Callback triggered - ContextListener.");
}
}
Ref:
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java#L1332

Spring AOP : Can we access bean object by getBean("beanName") method after applying ProxyFactoryBean on that Bean?

I have applied a 'BeforeAdvice' through 'ProxyFactoryBean' on a Bean of type "MyXMLApplication" now I am not able to access the Bean object directly{by getBean(MyXMLApplication.class)}, it is giving error :-
by setter dependency injection myxml
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.di.consumer.MyXMLApplication] is defined: expected single matching bean but found 2: MyXMLApp,proxy
However I am able to get the bean object by "proxy" bean object{(MyXMLApplication)context.getBean("proxy")}. Now my question is after applying proxy on any bean is there any way to access it directly without proxy bean.
My code is:
********Before Advisor*********
public class MyBeforeAdvisor implements MethodBeforeAdvice{
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
// TODO Auto-generated method stub
System.out.println("before advice run");
}
}
*********applicationContext.xml********
<bean id="twitter" class="com.journaldev.spring.di.services.TwitterService"></bean>
<bean id="MyXMLApp" class="com.journaldev.spring.di.consumer.MyXMLApplication" autowire="byType"/>
<bean id="beforeAdvice" class="com.journaldev.spring.aop.advisor.MyBeforeAdvisor"></bean>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="MyXMLApp"></property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
</list>
</property>
</bean>
**********Main Bean Class************
public class MyXMLApplication {
private MessageService service;
public void setService(MessageService svc){
System.out.println("by setter dependency injection myxml");
this.service=svc;
}
public boolean processMessage(String msg, String rec) {
return this.service.sendMessage(msg, rec);
}
}
**********Autowired Bean Interface *******
public interface MessageService {
boolean sendMessage(String msg, String rec);
}
**********Autowired Bean Impl*********
public class TwitterService implements MessageService {
public boolean sendMessage(String msg, String rec) {
System.out.println("Twitter message Sent to "+rec+ " with Message="+msg);
return true;
}
}
************* Main function**********
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MyXMLApplication app = context.getBean(MyXMLApplication.class); --> Not Working
//MyXMLApplication app = (MyXMLApplication)context.getBean("proxy"); -->working
app.processMessage("Hi", "abc#abc.com");
context.close();
}
Sorry guys, the error was coming because I was calling getBean(MyXMLApplication.class) [by type] that is why it founds two beans "proxy" and "MyXMLApp" of type MyXMLApplication.class and giving the error.
It is not something like we can not call the 'getBean'method on bean directly after applying any proxy on that.

Passing arguments from BatchJob to Tasklet in Spring Batch

To all Spring enthusiasts, here's a good challenge. Hope someone can crack it!!!
I use Spring to batch the extraction process. I have two classes 'ExtractBatchJob' and 'TaskletImpl'
public class ExtractBatchJob {
/** Logger for current class */
private static Log log = LogFactory.getLog(Extractor.class);
public static void main(String[] args)
throws IOrganizationServiceRetrieveMultipleOrganizationServiceFaultFaultFaultMessage,
IOException {
ApplicationContext context = new ClassPathXmlApplicationContext(
"/META-INF/cxf/batch-context.xml");
SpringBusFactory factory = new SpringBusFactory(context);
Bus bus = factory.createBus();
SpringBusFactory.setDefaultBus(bus);
IOrganizationService service = (IOrganizationService) factory
.getApplicationContext().getBean("service");
JobLauncher jobLauncher = (JobLauncher)context.getBean("jobLauncher");
Job job = (Job) context.getBean("firstBatchJob");
try {
JobExecution execution = jobLauncher.run(job, new JobParameters());
}catch (Exception e){
e.printStackTrace();
}
}
The second class TaskletImpl implements the Spring Tasklet interface.
public class TaskletImpl implements Tasklet {
/** Logger for current class */
private static Log log = LogFactory.getLog(CRMExtractor.class);
/* (non-Javadoc)
* #see org.springframework.batch.core.step.tasklet.Tasklet#execute(org.springframework.batch.core.StepContribution, org.springframework.batch.core.scope.context.ChunkContext)
*/
#Overridepublic RepeatStatus execute(StepContribution arg0, ChunkContext arg1)
throws Exception {
// TODO Auto-generated method stub
log.info("************ CRM Extraction Batch Job is executing!!! *******");
//QUESTION: To Extract Entity from third party
// web service need object reference for
//factory and service from ExtractBatchjob class
List<Entity> orderEntities = getEntities("orderQueryImpl", factory, service);
OrderDao orderDao = (OrderDao) factory.getApplicationContext()
.getBean("orderDao");
orderDao.batchInsert(orderEntities);*/
return RepeatStatus.FINISHED;
}
public static List<Entity> getEntities(String queryImpl, SpringBusFactory factory,
IOrganizationService service)
throws IOrganizationServiceRetrieveMultipleOrganizationServiceFaultFaultFaultMessage,
IOException {
QueryBuilder queryBuilder = (QueryBuilderTemplate) factory
.getApplicationContext().getBean(queryImpl);
QueryExpression queryExpr = queryBuilder.getQuery();
EntityCollection result = service
.retrieveMultiple(queryExpr);
return result.getEntities().getEntities();
}
}
Below is the snippet of the context file
`<import resource="cxf.xml" />
<bean id="firstBatch" class="com.abc.model.TaskletImpl" />
<batch:step id="firstBatchStepOne">
<batch:tasklet ref="firstBatch" />
</batch:step>
<batch:job id="firstBatchJob">
<batch:step id="stepOne" parent="firstBatchStepOne" />
</batch:job>`
My question is quite straightforward, how do I pass the two variables/objects 'service' and 'factory' to the TaskletImpl class from the ExtractBatchJob class.
The cleanest solution is to wire service and factory using Spring injection mechanism.
You have two solution:
Create SpringBusFactory as Spring bean and wire it into tasklet
Define a ContextBean (as singleton) for you job, create SpringBusFactory and set it as property of ContextBean; wire this bean to your tasklet
If you want to use object created outside Spring context (with new I meant) must be injected into Spring context.

Understanding basic Spring Framework and Total Flow

I am new to the Spring Framework. Please guide me regarding basic understanding of Spring. I know Java and JSF, but I don't know anything about Struts or other frameworks. I have searched the Internet and was able to download a PDF, but I don't understand the Spring flow like I understand JSF flow. Please provide me with links for a simple way to understand Spring's flow.
Transition 1 – User sends request to server by submitting form / by
clicking hyperlink etc. Request is initially given to WEB.XML.
Transition 2 – WEB.XML routes request to DispatcherServlet by looking
at tag.
Transition 3 – Inside DispatcherServlet,
First ‘HandlerMapping’ handed over request to suitable ‘Controller’.
Transition 4 – Controller maps request to proper Model class. All
BUSINESS LOGIC is done inside Model class.
Transition 5 – If database
operation is needed then Model class will route request to suitable
DAO. All database operations should be carried out in DAO.
Transition6 – If needed then attach attributes into request/session/application
scope and return back to Model.
Transition 7 – If needed then attach
attributes into request/session/application scope and return back to
Controller.
Transition 8 – Controller simply returns it to any View
(JSP/HTML etc).
Transition 9 – JSP/Html is viewed back to user.
Spring MVC Application Flow:
I'm new to Spring Framework too.
Up to now, the document below is the most basic one. I'm reading it as well, hope it could help you.
Introduction to Spring Framework
I am new to Spring too and time ago had similar question. First of all I want to recommend you 'Spring in Action' book by Craig Walls, I found it very usefull and easy to understand, also
http://www.tutorialspoint.com/spring/ helped me to figure many things out. If I understood your question right, then we can divide “Spring's flow” into Spring IoC container's and Spring bean's life cycles. Here is very small overview with exapmle on Spring bean's life cycle. A bean goes through several steps between creation and destruction in the Spring
container. These steps are:
Instantiate
Populate properties
BeanNameAware`s setBeanName()
BeanFactoryAware`s setBeanFactory
ApplicationContextAware`s setApplicationContext()
Pre-initialization BeanPostProcessors
InitializingBean`s afterPropertiesSet()
Call custom init-method
Post-initialization BeanPostProcessors
DisponsableBean`s destroy
Call custom destroy-method
Each step provides own oportunities for customization. Here is some code which simply “traces” bean`s life:
For bean ClassA:
public class ClassA implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware{
private String messageA;
public ClassA() {
System.out.println("ClassA: default constructor called.");
}
public void customInitMethod(){
System.out.println("ClassA: customInitMethod() method called.");
}
public void customDestroyMethod(){
System.out.println("ClassA: customDestroyMethod() method called.");
}
public String getMessageA() {
System.out.println("ClassA: message get method called.");
return messageA;
}
public void setMessageA(String message) {
System.out.println("ClassA: message set method called.");
this.messageA = message;
}
public void afterPropertiesSet() throws Exception {
System.out.println("ClassA: afterPropertiesSet() called because InitializingBean interface.");
}
public void destroy() throws Exception {
System.out.println("ClassA: destroy() called because DisposableBean interface.");
}
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
System.out.println("ClassA: application context set: " + arg0.getApplicationName());
}
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out.println("ClassA: beanFacrory set.");
}
public void setBeanName(String arg0) {
System.out.println("ClassA: bean name set: " + arg0);
}
}public class ClassA implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware{
private String messageA;
public ClassA() {
System.out.println("ClassA: default constructor called.");
}
public void customInitMethod(){
System.out.println("ClassA: customInitMethod() method called.");
}
public void customDestroyMethod(){
System.out.println("ClassA: customDestroyMethod() method called.");
}
public String getMessageA() {
System.out.println("ClassA: message get method called.");
return messageA;
}
public void setMessageA(String message) {
System.out.println("ClassA: message set method called.");
this.messageA = message;
}
public void afterPropertiesSet() throws Exception {
System.out.println("ClassA: afterPropertiesSet() called because InitializingBean interface.");
}
public void destroy() throws Exception {
System.out.println("ClassA: destroy() called because DisposableBean interface.");
}
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
System.out.println("ClassA: application context set: " + arg0.getApplicationName());
}
public void setBeanFactory(BeanFactory arg0) throws BeansException {
System.out.println("ClassA: beanFacrory set.");
}
public void setBeanName(String arg0) {
System.out.println("ClassA: bean name set: " + arg0);
}
}
For CustomPostProcessor:
public class CustomPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("CustomPostProcessor: beforeInitialization on: "
+ beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("CustomPostProcessor: afterInitialization on: "
+ beanName);
return bean;
}
}
In main class we creating ApplicationContext, getting bean and printing message out:
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
"META_INF/spring/app-context.xml");
ClassA objA = (ClassA) context.getBean("classA");
System.out.println(objA.getMessageA());
context.registerShutdownHook();
}
In app-context.xml we have:
<bean id="classA" class="ClassA" init-method="customInitMethod"
destroy-method="customDestroyMethod">
<property name="messageA" value="messagA: Hello Spring!" />
</bean>
<bean class="CustomPostProcessor" />
As I understand output lines correspond to life cycle stages this way:
1.Instantiate
ClassA: default constructor called.
2.Populate properties
ClassA: message set method called.
3.BeanNameAware`s setBeanName()
ClassA: bean name set: classA
4.BeanFactoryAware`s setBeanFactory
ClassA: beanFacrory set.
5.ApplicationContextAware`s setApplicationContext()
ClassA: application context set:
6.Pre-initialization BeanPostProcessors
CustomPostProcessor: beforeInitialization on: classA
7.InitializingBean`s afterPropertiesSet()
ClassA: afterPropertiesSet() called because InitializingBean interface.
8.Call custom init-method
ClassA: customInitMethod() method called.
9.Post-initialization BeanPostProcessors
CustomPostProcessor: afterInitialization on: classA
Program prints message
ClassA: message get method called.
messagA: Hello Spring!
10.DisponsableBean`s destroy
ClassA: destroy() called because DisposableBean interface.
11.Call custom destroy-method
ClassA: customDestroyMethod() method called.

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

Resources