Spring bean destroy-method , singleton and prototy

2019-01-19 10:35发布

问题:

I am new to the spring framework, started with some tutorials to learn it.

I have following files,

# MainProgram.java

package test.spring;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainProgram {
        public static void main(String[] args) {
              AbstractApplicationContext context = 
                              new ClassPathXmlApplicationContext("Bean.xml");     
              HelloSpring obj = (HelloSpring) context.getBean("helloSpring");
              obj.setMessage("My message");
              obj.getMessage();
              context.registerShutdownHook();

        }
 }

# HelloSpring.java

package test.spring;

public class HelloSpring   {
     private String message;

     public void setMessage(String message){
      this.message  = message;
      System.out.println("Inside setMessage");
   }

   public void getMessage(){
      System.out.println("Your Message : " + this.message);
   }

   public void xmlInit() {
    System.out.println("xml configured  initialize");
   } 

    public void xmlDestroy() {
    System.out.println("xml configured destroy");
    }

  }

# Bean.xml

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

     <bean id="helloSpring" class="test.spring.HelloSpring" 
          scope="prototype" init-method="xmlInit" destroy-method="xmlDestroy">

     </bean>
     </beans>

When I take scope="singleton" my output is :

 xml configured  initialize
 Inside setMessage
 Your Message : My message
 xml configured destroy

When I take scope="prototype" my output is :

 xml configured  initialize
 Inside setMessage
 Your Message : My message

xmlDestroy() method is called with singleton scope bean but not with prototype kindly help me for the following ,

Is this correct? if so, what would be possible reasons?

Also I have some queries like,

what is difference or relation between ApplicationContext , AbstractApplicationContext and ClassPathXmlApplicationContext

回答1:

xmlDestroy() method is called with singleton scope bean but not with prototype because

Spring does not manage the complete lifecycle of a prototype bean: the container instantiates, configures, decorates and otherwise assembles a prototype object, hands it to the client and then has no further knowledge of that prototype instance. For releasing resources try to implement a custom bean post processor.

Unlike singleton beans where the spring container manages the complete life-cycle

You can have a look at this basic tutorial for differences between different contexts

Refer documentation



回答2:

A singleton bean means that there is exactly one instance of that bean in the application context. That means if you do something like this:

HelloSpring obj = (HelloSpring) context.getBean("helloSpring");
    obj.setMessage("My message");
    System.out.printIn(obj.getMessage());
    HelloSpring anotherObj = (HelloSpring) context.getBean("helloSpring");
    System.out.printIn(anotherObj.getMessage());

You will see "My message" in the console output twice.

For prototype beans everytime you try to get one of those from the application context you will get a new instance so if you run the above code again the second console output will be "null".

As there is no need for the container to call a destroy method for a prototype bean, it does not and the behavior is correct.

The difference between the said classes are that they are an interface, an abstract class and a concrete class respectively, to understand better about that concepts I suggest reading the official oracle documentation for java in here Oracle Java Tutorials.



回答3:

This is the expected behaviour. There is no way for Spring to know when you have finished using a prototype scope bean, so bean destruction is not managed by Spring for prototype scoped beans. From the documentation:

Although initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called.

See the Spring documentation for more information.

With regards to ApplicationContexts, you can choose the one that is best-suited to your application. It depends whether you want to use XML or annotation bean configuration, and whether or not you are running in a servlet container, for example. ApplicationContext itself is the interface at the root of the type heirarchy.



回答4:

your application could ask for new instances of prototype beans every 10 milliseconds, do something with the bean, and then let it go out of scope. If Spring had to destroy() them when the application shuts down, it would have to keep a reference to every created prototype bean, preventing them to be garbage-collected, and thus causing a memory leak.



回答5:

I also tried to get a destroy event of bean which's scope is "prototype". So I read all answers above and try by their answers. At result, I reach out that there is no way to detect a destroy even of prototype bean.

Although initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called.

see here (https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-factory-scopes-prototype)



回答6:

Please check your scope type in your spring configuration file. If scope="prototype" then change it to scope="singleton"

<bean id="helloWorld" class="com.example.test.HelloWorld"
init-method="init" destroy-method="destroy">
<property name="message" value="Hello World!" />