when is a spring beans destroy-method called?
Asked Answered
N

6

26

I have put a sysout statement in the "destroy-method" for a bean. When i run a sample code, the sysout is not getting output. Does that mean the destroy-method is not getting called ?

The Test Class:

  package spring.test;

  import org.springframework.context.ApplicationContext;
  import org.springframework.context.support.ClassPathXmlApplicationContext;

  public class InitTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("InitTestContext.xml");
        InitTestBean bean = (InitTestBean)ctx.getBean("InitTestBean");
        bean.display();
    }
  }

The Bean

  package spring.test;

  public class InitTestBean {
    private String prop1;
    private String prop2;

    public InitTestBean(String prop1, String prop2) {
        System.out.println("Instantiating InitTestBean");
        this.prop1 = prop1;
        this.prop2 = prop2;
    }

    public void setProp1(String prop1) {
        System.out.println("In setProp1");
        this.prop1 = prop1;
    }

    public void setProp2(String prop2) {
        System.out.println("In setProp2");
        this.prop2 = prop2;
    }

    public String getProp1() {
        return prop1;
    }

    public String getProp2() {
        return prop2;
    }

    public void display() {
        System.out.println("Prop1 is " + prop1);
        System.out.println("Prop2 is " + prop2);
    }

    public void initialize(){
        System.out.println("In initialize");
        this.prop1 = "init-prop1";
        this.prop2 = "init-prop2";
    }

    public void teardown() {
        System.out.println("In teardown");
        this.prop1 = null;
        this.prop2 = null;
    }
  }

The Config file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="InitTestBean" class="spring.test.InitTestBean" init-method="initialize" destroy-method="teardown">
        <constructor-arg value="Prop1" />
        <constructor-arg value="Prop2" />
        <property name="prop1" value="setProp1"/>
        <property name="prop2" value="setProp2"/>
    </bean>

</beans>
Necromancy answered 16/12, 2010 at 11:40 Comment(4)
destroy-method works just fine. Show us your code and config.Gooding
It should be like thisRumba
You didn't have a trigger to let Spring know that you're closing down. As others pointed out, you need to let it know than closing the environment as a whole.Scatterbrain
If you have too many beans having initialization and or destroy methods with the same name, you don't need to declare init-method and destroy-method on each individual bean. Using default-init-method, default-destroy-method attributes on the <beans> elementHydrogen
G
40

Your example doesn't work because you're not shutting down the appcontext, you're just letting the program terminate.

Call close() on the context, and you'll see the bean destroy-methods being called.

Gooding answered 16/12, 2010 at 12:12 Comment(7)
There is no close method available on ApplicationContext.Necromancy
java_geek: It's not on that interface, it's on the implementation: ClassPathXmlApplicationContextGooding
even classpathxmlapplicationcontext does not have the close method.Necromancy
@java_geek: Yes, it does. It's on one of its superclasses.Gooding
This is great, but is there a way to ask the SpringJUnit4ClassRunner to do this for you? I have dozens of test class using this and the class runner does not appear to be closing the context upon completion of its tests. This gets frustrating as when each is run individually they are successful, but when run as a whole (via mvn package) they fail after enough of them are run without ever closing the connections properly.Cornet
The answer from @Life should be an accepted answer.Hydrogen
You need to cast your ApplicationContext to ClassPathXmlApplicationContext before calling the close method, in case you context type is ApplicationContext.Whitnell
M
24

It may be too late for the OP, but if someone is still looking for it...

The close method is in AbstractApplicationContext and not ApplicationContext, also another way is to use ctx.registerShutdownHook() instead of ctx.close() for obvious reasons that while running Junits you might want to close the context but not while in production environment so let Spring decide on when to close it.

Mauceri answered 24/4, 2012 at 20:9 Comment(3)
+ 1. Check this out : tutorialspoint.com/spring/spring_bean_life_cycle.htmHydrogen
Is there any way to close it by itself automatically by timeout. Say I have kept my app in my server idle for a week. Will it close at some point? Will the destroy method gets called during that time ?Valor
@vsriram You could make your own thread or runnable that handles that by making it call ctx.close() when your conditions happen. Otherwise, it won't be called by itself as long as your server and jvm is upSpann
S
7

The "destroy-method" is only called if and only if the bean is a singleton instance

See the log output of the IOC container

INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1a0ce4c: defining beans [book1]; root of factory hierarchy

Sonata answered 16/10, 2013 at 8:29 Comment(2)
This was the real answer for me. I was struggling to understand why close and registerShutdownHook were not working.Morganatic
This should be the accepted answer. I too was struggling with my destroy method not called when the type of bean was prototype.Kepner
K
6
//Getting application context
ApplicationContext context = new ClassPathXmlApplicationContext(beansXML); 

//cleaning context
((ClassPathXmlApplicationContext) context).close(); 
Kidd answered 25/10, 2012 at 20:31 Comment(0)
L
2

hi you need to change ApplicationContext to AbstractApplicationContext and then register to a ShutDownhook which will destroy your bean and also implement the DisposableBean interface eg:

  package spring.test;

  import org.springframework.context.ApplicationContext;
  import org.springframework.context.support.ClassPathXmlApplicationContext;
  import org.springframework.context.support.AbstractApplicationContext;
  public class InitTest {
    public static void main(String[] args) {
       AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("InitTestContext.xml");
  ctx.registerShutdownHook();
        InitTestBean bean = (InitTestBean)ctx.getBean("InitTestBean");
        bean.display();
    }
  }

and now implemnt the DisposableBean interface

package spring.test;
import org.springframework.beans.factory.DisposableBean;
  public class InitTestBean implements DisposableBean{
    private String prop1;
    private String prop2;
    public InitTestBean(String prop1, String prop2) {
        System.out.println("Instantiating InitTestBean");
        this.prop1 = prop1;
        this.prop2 = prop2;
    }
    public void setProp1(String prop1) {
        System.out.println("In setProp1");
        this.prop1 = prop1;
    }
    public void setProp2(String prop2) {
        System.out.println("In setProp2");
        this.prop2 = prop2;
    }
    public String getProp1() {
        return prop1;
    }
    public String getProp2() {
        return prop2;
    }
    public void display() {
        System.out.println("Prop1 is " + prop1);
        System.out.println("Prop2 is " + prop2);
    }
    public void initialize(){
        System.out.println("In initialize");
        this.prop1 = "init-prop1";
        this.prop2 = "init-prop2";
    }
    public void teardown() {
        System.out.println("In teardown");
        this.prop1 = null;
        this.prop2 = null;
    }
    @Override
    public void destroy() throws Exception {

        System.out.println(" the bean has been destroyed");
    }
  }
Lightness answered 18/3, 2013 at 7:7 Comment(0)
B
1

factory.destroySingletons(); after your bean.display() as destroy-method is valued in the bean definition. The default scope with which bean is created is singleton hence, invoking the factory.destroySingletons() will call the method mentioned in the destroy-method.

Brion answered 18/6, 2013 at 15:29 Comment(1)
Could you please add more detail or explanation? Your current answer is so sparse that it is likely to be deleted.Claytor

© 2022 - 2024 — McMap. All rights reserved.