The scope and lifecycle of beans in spring

Source: Internet
Author: User
Tags deprecated

In spring, the bodies that make up the application and the objects managed by the spring IOC container are called beans. Simply put, the bean is the object that is initialized, assembled, and managed by the IOC container, and in addition, the bean is no different from the other objects in the application. The definition of the bean and the dependencies between the beans are described by configuring metadata.

The beans in spring are, by default, a single example of how the single bean is guaranteed to be thread-safe under multithreaded routines. For example, for a Web application, the Web container creates a separate Sevlet thread for each user request to process the request, and after the spring framework is introduced, each action is a singleton, so how do you secure the Singleton service Bean hosted by spring? The singleton of Spring is based on the beanfactory, the spring container, where the singleton Bean has only one, and the Java Singleton is based on the JVM, with only one instance in each JVM. 1, the scope of the bean

Create a bean definition that essentially uses the bean to define the corresponding class to create a "recipe" for the real instance. It makes sense to think of a bean definition as a recipe, which is similar to class, where multiple instances can be created with a single "prescription". You can control not only the various dependencies and configuration values injected into the object, but also the scope of the object. This allows you to flexibly select the scope of the object you are building without having to define the scope at the Java class level. The Spring framework supports five scopes, each of which describes the following table.

Of the five scopes, request, session, and global session three scopes are only used in web-based applications (not to mention what Web application framework you are using), but only for web-based spring ApplicationContext environment.

(1) When a bean is scoped to a singleton, only one shared bean instance exists in the spring IOC container, and all requests to the bean, as long as the ID matches the bean definition, return only the same instance of the bean. Singleton is a single instance type that automatically creates a bean object when the container is created, regardless of whether you are using it or not, and each time you get the object is the same object. Note that the singleton scope is the default scope in spring. To define a bean as singleton in XML, you can configure it like this:

<bean id= "Serviceimpl" class= "Cn.csdn.service.ServiceImpl" scope= "singleton" >

(2) When a bean's scope is prototype, it means that a bean definition corresponds to multiple object instances. A prototype-scoped bean causes a new bean instance to be created each time the bean is requested (injected into another bean, or the container's Getbean () method is invoked programmatically). Prototype is a prototype type that is not instantiated when we create a container, but rather when we get the bean to create an object, and each time we get the object is not the same object. Based on experience, you should use the prototype scope for stateful beans, whereas stateless beans should use the singleton scope. The bean is defined as prototype in XML, and can be configured like this:

<bean id= "Account" class= "Com.foo.DefaultAccount" scope= "prototype"/>  
 or

(3) When a bean's scope is request, it means that in an HTTP request, a bean definition corresponds to an instance, that is, each HTTP request will have its own bean instance, which is created from a bean definition. This scope is only valid under the Web-based spring applicationcontext scenario. Consider the following Bean definition:

<bean id= "loginaction" class=cn.csdn.loginaction "scope=" Request "/>

For each HTTP request, the spring container creates a completely new loginaction Bean instance based on the definition of the loginaction bean, and the loginaction bean instance is valid only within the current HTTP requests. As a result, you can change the internal state of the instance you are building on the basis of your needs, and the instances created by the loginaction bean definition in other requests will not see the state changes that are specific to a request. When the processing request is complete, the bean instance of the request scope is destroyed.

(4) When a bean's scope is session, it means that in an HTTP session, a bean definition corresponds to an instance. This scope is only valid under the Web-based spring applicationcontext scenario. Consider the following Bean definition:

<bean id= "userpreferences" class= "Com.foo.UserPreferences" scope= "Session"/>

For an HTTP session,spring container, a new userpreferences Bean instance is created based on the userpreferences bean definition, and the userpreferences Bean is only in the current HTTP Valid during session. As with the request scope, you can change the internal state of the created instance as needed, and the instances created by Userpreferences in other HTTP sessions will not see the state changes that are specific to an HTTP session. When the HTTP session is eventually discarded, the bean in the HTTP session scope is also discarded.

(5) When a bean's scope is global session, it means that in a global HTTP session, a bean definition corresponds to an instance. Typically, this is only valid when using the Portlet context. This scope is only valid under the Web-based spring applicationcontext scenario. Consider the following Bean definition:

<bean id= "user" class= "com.foo.Preferences" scope= "Globalsession"/>

The global session scope is similar to the standard HTTP session scope, but is only meaningful in a portlet-based Web application. The Portlet specification defines the concept of a global session, which is shared by all of the different portlets that make up a portlet Web application. The bean defined in the global session scope is limited to the lifecycle scope of the globally portlet session. 2, the bean life cycle

The instantiation process of the bean in spring (sorry, I stole the map):

Similar to the figure above, the life cycle flowchart of the Bean:

The execution of the bean instance lifecycle is as follows:

The bean is instantiated by spring, and the default bean is a single case;

Spring relies on the bean for injection;

If the bean implements the Beannameaware interface, spring passes the Bean's ID to the Setbeanname () method;

If the bean implements the Beanfactoryaware interface, spring will call the Setbeanfactory method and pass in the Beanfactory instance;

If the bean implements the Applicationcontextaware interface, its Setapplicationcontext () method is invoked and the reference to the application context is passed into the bean;

If the bean implements the Beanpostprocessor interface, its Postprocessbeforeinitialization method will be invoked;

If the bean implements the Initializingbean interface, spring will call its Afterpropertiesset interface method, which is also invoked if the bean declares an initialization method using the Init-method property;

If the bean implements the Beanpostprocessor interface, its Postprocessafterinitialization interface method will be invoked;

The beans are now ready to be used by the application, and they will reside in the application context until the application context is destroyed;

If the bean implements the Disposablebean interface, spring will call its Distroy () interface method. Similarly, if the bean uses the Destroy-method property to declare the destruction method, the method is invoked;

In fact, many times we are not really going to implement the interface described above, then we will remove those interfaces, for the Bean's single and non-single example to describe the life cycle of the next Bean: 2.1 Single managed Objects

When scope= "Singleton", which is by default, is instantiated when the container is started (that is, when the container is instantiated). However, we can specify lazy-init= "true" of the bean node to delay initialization of the bean, at which point the bean is initialized only the first time the bean is fetched, that is, it is initialized the first time the bean is requested. Configuration as follows:

<bean id= "Serviceimpl" class= "Cn.csdn.service.ServiceImpl" lazy-init= "true"/>  

If you want to apply deferred initialization to all of the default single instance beans, you can set the Default-lazy-init property to True at the root node beans, as follows:

<beans default-lazy-init= "true" ...>

By default, Spring creates an object when it reads an XML file. The constructor is called first when the object is created, and then the method specified in the Init-method property value is invoked. When an object is destroyed, it invokes the method specified in the value of the Destroy-method property (for example, when the Container.destroy () method is invoked). Write a test class with the following code:

public class Lifebean {
    private String name;  

    Public Lifebean () {  
        System.out.println ("Lifebean () constructor");  
    }  
    Public String GetName () {return  
        name;  
    }  

    public void SetName (String name) {  
        System.out.println ("SetName ()");  
        this.name = name;  

    public void init () {  
        System.out.println (' This is init ' Lifebean ');  
    }  

    public void Destory () {  
        System.out.println (' This is destory of Lifebean ' + this);  
    }  
}

The Life.xml configuration is as follows:

<bean id= "Life_singleton" class= "Com.bean.LifeBean" scope= "singleton" " 
            init-method=" init "destroy-method=" Destory "lazy-init=" true "/>

The test code is as follows:

public class Lifetest {
    @Test public 
    void Test () {
        Abstractapplicationcontext container = 
        New Classpathxmlapplicationcontext ("Life.xml");
        Lifebean life1 = (Lifebean) Container.getbean ("Life");
        System.out.println (LIFE1);
        Container.close ();
    }

The results of the operation are as follows:

Lifebean () constructor is
init of Lifebean com.bean.lifebean@573f2bb1 ...
This is destory of Lifebean COM.BEAN.LIFEBEAN@573F2BB1
2.2 Non-single managed objects

When scope= "prototype", the container also delays initialization bean,spring reads the XML file, does not create the object immediately, but initializes it the first time the bean is requested (for example, when the Getbean method is invoked). When each prototype Bean is requested for the first time, the spring container invokes its constructor to create the object and then invokes the method specified in the Init-method property value. When the object is destroyed, the spring container does not call any methods, because it is not a single case, there are many objects of this type, and the spring container will not manage the object once it has been handed to you.

To test the lifecycle of the prototype Bean Life.xml configuration is as follows:

<bean id= "Life_prototype" class= "Com.bean.LifeBean" scope= "prototype" "Init-method=" Init "destroy-method=" destory "/>

The test procedure is as follows:

public class Lifetest {
    @Test public 
    void Test () {
        Abstractapplicationcontext container = new Classpathxmlapplicationcontext ("Life.xml");
        Lifebean life1 = (Lifebean) container.getbean ("Life_singleton");
        System.out.println (LIFE1);

        Lifebean Life3 = (Lifebean) container.getbean ("Life_prototype");
        System.out.println (LIFE3);
        Container.close ();
    }

The results of the operation are as follows:

The Lifebean () constructor is
init of Lifebean
com.bean.lifebean@573f2bb1
Lifebean () constructor is
init of Lifebean
com.bean.lifebean@5ae9a829 ...
This is destory of Lifebean COM.BEAN.LIFEBEAN@573F2BB1

It can be found that the destroy method for a prototype-scoped bean is not invoked. If the bean's scope is set to prototype, the Destroy method is not invoked when the container closes. For prototype-scoped beans, it is important that spring cannot be responsible for the entire lifecycle of a prototype bean: The container is delivered to the client after it is initialized, configured, decorated, or a prototype instance is assembled. The prototype instance was then ignored. Regardless of the scope, the container invokes the initialization lifecycle callback method for all objects. However, for prototype, any configured destructor lifecycle callback method will not be invoked. It is the responsibility of the client code to clear the object of the prototype scope and to release any expensive resources held by any prototype bean (a viable way for the spring container to release the resources of the prototype scope bean is by using the Bean's back processor , the processor holds a reference to the bean to be purged. When it comes to prototype scoped beans, in some ways you can view the role of the spring container as a substitute for the Java new operation, and any life cycle matters later than that point have to be handled by the client.

The spring container can manage the lifecycle of the bean under the singleton scope, where spring is able to know exactly when the bean was created, when initialization was completed, and when it was destroyed. For the bean,spring of the prototype scope, which is created only, when the container creates an instance of the bean, the instance of the bean is given to the client for code management, and the spring container will no longer track its lifecycle. And does not manage the lifecycle of beans that are configured as prototype scopes. 2.3 Extension

During the learning of spring IOC, it was found that each time the ApplicationContext factory was produced:

ApplicationContext ApplicationContext = new Classpathxmlapplicationcontext ("Applicationcontext.xml");

There is a drawback to this generation of ApplicationContext, which produces the factory every time it accesses the load bean, so this problem needs to be addressed here.

ApplicationContext is an interface that inherits from the Beanfactory interface and is well supported in terms of internationalization support, resource access (such as URLs and files), and event propagation, in addition to all the functions that contain beanfactory.

The solution to the problem is simply to move the ApplicationContext to ServletContext when the Web container is started, because all servlet shares a ServletContext object in the Web application. Then we can use Servletcontextlistener to monitor the ServletContext event, and when the Web application starts, we load the ApplicationContext into ServletContext. The spring container bottom has already thought of this for us, there is a class Contextloader in the Spring-web-xxx-release.jar package that has already implemented the Servletcontextlistener interface, and its source code is as follows:

public class Contextloaderlistener extends Contextloader implements Servletcontextlistener {private Contextloader con

    Textloader; Public Contextloaderlistener () {} public Contextloaderlistener (Webapplicationcontext context) {super (C
    Ontext);
        public void contextinitialized (Servletcontextevent event) {This.contextloader = Createcontextloader ();
        if (This.contextloader = = null) {This.contextloader = this;
    } this.contextLoader.initWebApplicationContext (Event.getservletcontext ());
    @Deprecated protected Contextloader Createcontextloader () {return null;
    @Deprecated public Contextloader Getcontextloader () {return this.contextloader; public void contextdestroyed (Servletcontextevent event) {if (This.contextloader!= null) {this.co
        Ntextloader.closewebapplicationcontext (Event.getservletcontext ()); } contextcleanuplistener.cLeanupattributes (Event.getservletcontext ()); }
}

This is where you hear the ServletContext creation process, so how does this class fit applicationcontext into the Serveletcontext container?

The specific implementation of the This.contextLoader.initWebApplicationContext (Event.getservletcontext ()) Method:

Public Webapplicationcontext Initwebapplicationcontext (ServletContext servletcontext) {if (servletcontext.getattrib
                 Ute (Webapplicationcontext.root_web_application_context_attribute)!= null) {throw new IllegalStateException (
                 "Cannot initialize context because there are already a root application context present-" +
     "Check whether you have multiple contextloader* definitions in your web.xml!");
     Log logger = Logfactory.getlog (Contextloader.class);
     ServletContext.log ("Initializing Spring root Webapplicationcontext");
     if (logger.isinfoenabled ()) {Logger.info ("Root webapplicationcontext:initialization started");

     Long starttime = System.currenttimemillis (); try {//Store context in the local instance variable, to guarantee that//it is available on Servletcont
         Ext shutdown. if (This.context = = null) {This.context = Createwebapplicationcontext (Servletcontext);  } if (This.context instanceof configurablewebapplicationcontext) {Configurablewebapplicationcontext
             CWAC = (configurablewebapplicationcontext) this.context;
                 if (!cwac.isactive ()) {//the context has not yet been refreshed-> provide services such as Setting the parent context, setting the application context ID, etc if (cwac.getparent () = n ULL) {//The context instance is injected without an explicit parent->//
                     Determine parent for root Web application The context, if any.
                     ApplicationContext parent = Loadparentcontext (ServletContext);
                 Cwac.setparent (parent);
             } configureandrefreshwebapplicationcontext (CWAC, ServletContext); } servletcontext.setattribute (Webapplicationcontext.root_web_application_context_attribute, This.conte XT);
         ClassLoader CCL = Thread.CurrentThread (). Getcontextclassloader ();
         if (CCL = = ContextLoader.class.getClassLoader ()) {currentcontext = This.context;
         else if (CCL!= null) {Currentcontextperthread.put (CCL, this.context); } if (logger.isdebugenabled ()) {Logger.debug ("published Root webapplicationcontext as Servletconte
         XT attribute with Name ["+ Webapplicationcontext.root_web_application_context_attribute +]");
             } if (logger.isinfoenabled ()) {Long elapsedtime = System.currenttimemillis ()-starttime;
         Logger.info ("Root Webapplicationcontext:initialization completed in" + ElapsedTime + "MS");
     return this.context;
         catch (RuntimeException ex) {Logger.error ("context initialization failed", ex); Servletcontext.setattribute (Webapplicationcontext.root_web_application_context_ATTRIBUTE, ex);
     Throw ex;
         catch (Error err) {Logger.error ("context initialization failed", err);
         Servletcontext.setattribute (Webapplicationcontext.root_web_application_context_attribute, err);
     throw err; }
 }

The focus here is Servletcontext.setattribute (Webapplicationcontext.root_web_application_context_attribute, This.context), With Key:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE value: This.context the form of the ApplicationContext loaded into the ServletContext. In addition, from some of the above comments we can see: Web-inf/applicationcontext.xml, if the configuration file in our project is not such a path, then we use Contextloaderlistener will have problems, So we also need to configure the path of our applicationcontext.xml configuration file in Web.xml.

<listener>
    <listener-class>org.springframework.web.context.contextloaderlistener</ listener-class>
</listener>

<context-param>
    <param-name>contextconfiglocation </param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</ Context-param>

The rest is to start using the ApplicationContext object loaded in the ServletContext in the project: So here's another problem, the key to load is Webapplicationcontext.root_web_ Application_context_attribute, do we really want to use this in code? In fact, Spring provides us with a tool class webapplicationcontextutils, and then we look at how to use it and then look at the source code for the tool class:

Webapplicationcontext ApplicationContext = Webapplicationcontextutils.getwebapplicationcontext ( Request.getservletcontext ());

Then look at the source code for this tool class:

public static Webapplicationcontext Getwebapplicationcontext (ServletContext SC) {return
    Getwebapplicationcontext (SC, webapplicationcontext.root_web_application_context_attribute);

This is a straightforward way to see the ApplicationContext object loaded into the ServletContext directly from the key value.

The role of the Contextloaderlistener listener is to automatically assemble the ApplicationContext configuration information when the Web container is started, because it implements the Servletcontextlistener interface, When you configure this listener in Web.xml, when you start the container, the method that it implements is executed by default. Contextloader is associated with this class in Contextloaderlistener, and the entire load configuration process is done by Contextloader.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.