Start source code of Spring IoC container in Web Environment

Source: Internet
Author: User

Note: The source code in this blog is based on spring3.1.

Because of its low skills, the writing is not nutritious and only helps you understand what you have learned. Although it is called a blog, it is actually your learning notes...

1. Web environment-related IOC container class diagram in spring

First, let's take a look at some of the IOC container class inheritance relationships related to the web environment in Spring:

In the class inheritance relationships shown in, the IOC container of spring in the web environment is connected to the beanfactory basic IOC container through the applicationcontext interface. Many of the basic functions of IOC are implemented through the abstractrefreshablewebapplicationcontext abstract class, this class inherits the abstractrefreshableconfigapplicationcontext abstract class, which is connected to the non-web advanced IOC container.

2. Use of spring in the Web Environment

Spring can be used in the web environment in two ways:

1. Start with the contextloaderlistener listener;

2. Start with the contextloaderservlet configured as load-on-startup (this class is not recommended and has been removed from spring3.x ).

In these two ways, it is more common to use listeners to start spring. To start spring, configure the following code in Web. xml:

<context-param><param-name>contextConfigLocation</param-name><param-value>classpath*:applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>

The contextloaderlistener here should obviously be a listener that complies with Java Servlet specifications, and spring should load the IOC container when the web application starts, therefore, contextloaderlistener implements the servletcontextlistener interface. Servletcontextlistener is the listener of servletcontext. This interface defines two methods: contextinitialized and contextdestroyed, which are called Based on the lifecycle of the Web container. The former is called during web application initialization, the latter is called when the web application is destroyed. Obviously, spring should create and start the IOC container in the contextinitialized method implementation, and destroy the IOC container in the contextdestroyed method implementation.

This article uses the contextloaderlistener listener as the entry to analyze the spring Startup Process in the Web environment. For details, see the following.

3. Start spring in the Web Environment

3.1 contextloaderlistener contextinitialized

When the Web Service is started, it notifies all servletcontextlistener listeners, calls the contextinitialized method, and uses contextloaderlistener as the implementation of the servletcontextlistener interface.

Next let's take a look at what contextloaderlistener listener completes in the contextinitialized method implementation when the web service is started:

/*** Initialize the root web application context when the web application starts */Public void contextinitialized (servletcontextevent event) {// The createcontextloader () method from spring3.0 is @ deprecated, we recommend that you use contextloaderlistener as contextloader. // from spring3.0, contextloaderlistener inherits the contextloader class this. contextloader = createcontextloader (); If (this. contextloader = NULL) {This. contextloader = This;} This. contextloader. initwebapplicationcontext (event. getservletcontext ());}

From the code above, we can see that in the contextinitialized method, contextloader is created first, and then its initwebapplicationcontext method is called to complete the IOC container initialization. However, the createcontextloader method for creating contextloader starting from spring3.0 is marked as @ deprecated and is not recommended. Instead, contextloaderlistener is directly inherited from the contextloader class, therefore, contextloaderlistener can initialize the IOC container (directly call the initwebapplicationcontext method of contextloader ).

From then on, the specific work is completed by the initwebapplicationcontext method of the contextloader class, And the servletcontext object obtained by the servletcontextevent event object is passed as a parameter.

3.2. initwebapplicationcontext of contextloader

Public webapplicationcontext initwebapplicationcontext (servletcontext) {// If the spring root context (IOC container) already exists in servletcontext, an exception if (servletcontext. getattribute (webapplicationcontext. root_web_application_context_attribute )! = NULL) {Throw new illegalstateexception ("Cannot initialize context because there is already a root application context present-" + "check whether you have multiple contextloader * Definitions in your web. xml! ");} // The Log Code is omitted long starttime = system. currenttimemillis (); // mark start time try {If (this. context = NULL) {This. context = createwebapplicationcontext (servletcontext); // start to create spring context} If (this. context instanceof configurablewebapplicationcontext) {configureandrefreshwebapplicationcontext (configurablewebapplicationcontext) This. context, servletcontext); // configure to start the IOC container} servletcontext. setattribute (webapplication Context. root_web_application_context_attribute, this. context); // put the IOC container in the servletcontext classloader CCL = thread. currentthread (). getcontextclassloader (); If (CCL = contextloader. class. getclassloader () {currentcontext = This. context;} else if (CCL! = NULL) {currentcontextperthread. put (CCL, this. context);} // some log codes are omitted. The current time is obtained below. If (logger. isinfoenabled () {long elapsedtime = system. currenttimemillis ()-starttime; logger.info ("root webapplicationcontext: initialization completed in" + elapsedtime + "Ms");} return this. context; // return spring context} catch () {// catch code block omitted }}

The spring root context is created in the Web container in the initwebapplicationcontext method of contextloader. This context exists as a unique instance in the Web Container. If the context already exists in the servletcontext during initialization, an exception is thrown to interrupt creation. The creation of context is divided into two steps from spring3.1: Create and start. In the previous version, the context is created in the createwebapplicationcontext (servletcontext SC, applicationcontext
Parent. After the context is created, it is stored in the servletcontext of the Web Container. You can obtain the context directly when necessary. The storage index is pre-defined by spring in the webapplicationcontext interface:

Public interface webapplicationcontext extends applicationcontext {string root_web_application_context_attribute = webapplicationcontext. Class. getname () + ". Root"; // other Code omitted}
3.3 create an IOC container

The creation process of the context object is defined in the createwebapplicationcontext method of contextloader:

Protected webapplicationcontext createwebapplicationcontext (servletcontext SC) {class <?> Contextclass = determinecontextclass (SC); // here the IOC container (root context type) if (! Configurablewebapplicationcontext. class. isassignablefrom (contextclass) {Throw new applicationcontextexception ("Custom context class [" + contextclass. getname () + "] is not of Type [" + configurablewebapplicationcontext. class. getname () + "]");} // instantiate the Class Object of the obtained IOC container and return configurablewebapplicationcontext WAC = (configurablewebapplicationcontext) beanutils. instantiateclass (contextclass); Return WAC ;}

In the createwebapplicationcontext method, call the determinecontextclass Method to Determine the Spring IoC container class to be used. After the IOC container is determined, the determinecontextclass method returns the Class Object of the IOC container class used, the program will instantiate it and return it directly. Note that the program only uses the beanutils tool class to instantiate the IOC container class and does not load beandefinition. Therefore, the IOC container here is just an empty object.

We will interrupt it here and go to the determinecontextclass method to see how the program decides the type of IOC container used:

Protected class <?> Determinecontextclass (servletcontext) {// from the web. get the contextclass parameter value configured in XML (context_class_param is a constant with the value contextclass) string contextclassname = servletcontext. getinitparameter (context_class_param); If (contextclassname! = NULL) {// if it is not null, we need to use the custom IOC container try {return classutils. forname (contextclassname, classutils. getdefaclasclassloader ();} catch (classnotfoundexception ex) {Throw new applicationcontextexception ("failed to load custom context class [" + contextclassname + "]", ex );}} else {// if no custom IOC container is configured, use the default IOC container implementation (xmlwebapplicationcontext class by default) contextclassname = defaultstrategies. getproperty (webapplicationcontext. class. getname (); try {return classutils. forname (contextclassname, contextloader. class. getclassloader ();} catch (classnotfoundexception ex) {Throw new applicationcontextexception ("failed to load default context class [" + contextclassname + "]", ex );}}}

The program shows that we can deploy the descriptor (web. the specified IOC container is similar to the specified configuration file location (the parameter name is also constant -- contextclass). If we do not specify the IOC container to be used, the program uses the default Spring IoC container: xmlwebapplicationcontext class. In the else statement block, we can see that the default IOC container class is obtained from defaultstrategies, and defaultstrategies is Java. util. the definition and initialization code of a constant of the properties type can be found in the declaration section of the contextloader class:

Private Static final string default_strategies_path = "contextloader. properties "; Private Static final properties defaultstrategies; static {try {// create a classpathresource pointing to the default_strategies_path file (default_strategies_path is a constant and the value is contextloader. properties) classpathresource resource = new classpathresource (default_strategies_path, contextloader. class); // call contextloader. the configuration items in the properties configuration file are loaded into the defaultstrategies member variable defaultstrategies = propertiesloaderutils. loadproperties (Resource);} catch (ioexception ex) {Throw new illegalstateexception ("cocould not load 'contextloader. properties ': "+ ex. getmessage ());}}

This is a static initialization block. The code is executed when the class is loaded. The Code shows that the initialization block is preferred to create a classpathresource to represent a resource in the class path, the resource file name is defined by a constant default_strategies_path. The constant value is contextloader. properties, that is, when the contextloader class is loaded, the static initialization block will go to the class path to find the name contextloader. properties configuration file, and load the content to the defaultstrategies constant.

We didn't provide the contextloader. properties configuration file in the class path. Where is this file? We can find this configuration file in the org. springframework. web-3.1.2.RELEASE.jar package provided by spring, which has only one line of configuration except annotations, as shown below:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

From this we can see that the default IOC container of spring in the web environment is indeed the xmlwebapplicationcontext class.

3.4 IOC container loading and Startup Process

The source code analysis shows that spring context objects (IOC containers) have been created, but the IOC container does not have the bean management function yet, because this is just an empty IOC container, bean definition has not been loaded. To load bean definitions and start the IOC container, contextloader calls another method: configureandrefreshwebapplicationcontext

The configureandrefreshwebapplicationcontext method is implemented as follows:

Protected void configureandrefreshwebapplicationcontext (configurablewebapplicationcontext WAC, servletcontext SC) {If (objectutils. identitytostring (WAC ). equals (WAC. GETID () {string idparam = SC. getinitparameter (context_id_param); // obtain the initialization ID parameter if (idparam! = NULL) {if the ID parameter is specified in the configuration file, the specified ID is used as the unique identifier of the context WAC. setid (idparam);} else {// No ID parameter is configured, the unique if (SC. getmajorversion () = 2 & SC. getminorversion () <5) {WAC. setid (configurablewebapplicationcontext. application_context_id_prefix + objectutils. getdisplaystring (SC. getservletcontextname ();} else {WAC. setid (configurablewebapplicationcontext. application_context_id_prefix + objectutils. Getdisplaystring (SC. getcontextpath () ;}} applicationcontext parent = loadparentcontext (SC); // load the parent context WAC. setparent (parent); // sets the parent context WAC. setservletcontext (SC); // store the servletcontext object string initparameter = SC. getinitparameter (config_location_param); // obtain the configured spring configuration file parameters (contextconfiglocation parameter) if (initparameter! = NULL) {WAC. setconfiglocation (initparameter); // set the spring configuration file} customizecontext (SC, WAC); WAC. Refresh (); // start IOC container initialization}

In the configureandrefreshwebapplicationcontext method, you first set a unique ID for the created IOC container, then set the parent context and spring configuration file, and finally call refresh to start the container.

So far, the spring context has been established and started in the web environment, and is also stored in the servletcontext. Spring has been started in the Web environment.

4. Obtain the spring context object (IOC container) in the Web Environment)

From the source code analysis above, we can understand that contextloader will exist in the servletcontext object after the IOC container (xmlwebapplicationcontext implementation) is created and started, as shown below:

Servletcontext. setattribute (webapplicationcontext. root_web_application_context_attribute, this. context); // put the IOC container into servletcontext

We can get the spring context object as follows when we need to use the IOC container in the program:

ApplicationContext context = (ApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

In addition, spring also provides the webapplicationcontextutils tool class, which also defines the methods to get the spring context getwebapplicationcontext and getrequiredwebapplicationcontext. The difference between the two is that if the current servletcontext does not have the corresponding spring Web Container, the former returns NULL, while the latter throws an exception. The source code is as follows:

Public static webapplicationcontext failed (servletcontext SC) throws illegalstateexception {webapplicationcontext WAC = getwebapplicationcontext (SC); If (WAC = NULL) {Throw new handle ("No webapplicationcontext found: no response registered? ");} Return WAC;} public static webapplicationcontext getwebapplicationcontext (servletcontext SC) {return getwebapplicationcontext (SC, webapplicationcontext. root_web_application_context_attribute);} public static webapplicationcontext getwebapplicationcontext (servletcontext SC, string attrname) {object ATTR = SC. getattribute (attrname); If (ATTR = NULL) {return NULL;} // partial exception judgment code return (webapplicationcontext) ATTR ;}

In fact, there is nothing magical, the same is webapplicationcontext. root_web_application_context_attribute calls servletcontext. the getattribute method is used to obtain the IOC container object. There are only a few other operations. Either method can be used, and the method used is based on your personal interests.

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.