SPRINGMVC Container Loading Source analysis

Source: Internet
Author: User

SPRINGMVC is a lightweight and flexible MVC framework based on a servlet container that, in order to be able to flexibly customize various requirements throughout its request, provides a series of components to complete the mapping, response, etc. of the entire Request. Here we analyze the source code of the Springmvc.

first, Spring provides a servlet that handles all requests, and this servlet implements the servlet interface, which is dispatcherservlet. Configure it in Web. XML and process the requests that we need to process throughout mvc, typically as Follows:

<servlet>
<servlet-name>spring-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring-servlet</servlet-name>
<url-pattern>/</url-pattern>
As you can see, Spring's container initialization for web support is triggered, and the container used here is Webapplicationcontext. let's analyze the initialization process for the entire container:

Protected Webapplicationcontext Initwebapplicationcontext () {
See if there is a root Web container in the servlet context that all containers need to inherit
Webapplicationcontext Rootcontext =
Webapplicationcontextutils.getwebapplicationcontext (getservletcontext ());
Webapplicationcontext WAC = null;
If the container is already loaded
If (this.webapplicationcontext! = Null) {
A Context instance is injected at construction time, use it
WAC = this.webapplicationcontext;
If (WAC instanceof Configurablewebapplicationcontext) {
Configurablewebapplicationcontext CWAC = (configurablewebapplicationcontext) wac;
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 () = = Null) www.yuheng119.com/{
The context instance is injected without an explicit parent, set
The root application context (if any; could be null) as the parent
Cwac.setparent (rootcontext);
}
Configureandrefreshwebapplicationcontext (cwac);
}
}
}
if (WAC = = Null) {
No Context instance is injected at construction time, see if one
have been registered in the servlet context. If one exists, it is assumed
That's The parent context (if Any) have already been set and that the
User have performed any initialization such as setting the context ID
WAC = Findwebapplicationcontext ();
}
if (WAC = = Null) {
Create a container
WAC = Createwebapplicationcontext (rootcontext);
}

If (!this.refresheventreceived) {
Either the context isn't a configurableapplicationcontext with refresh
Support or the context injected at construction time had already been
Refreshed-trigger Initial Onrefresh manually here.
Onrefresh (wac);
}

If (this.publishcontext) {
Publish the context as a servlet context Attribute.
String attrname = Getservletcontextattributename ();
Getservletcontext (). SetAttribute (attrname, wac);
If (this.logger.isDebugEnabled (www.xucaizxyl.com)) {
This.logger.debug ("Published Webapplicationcontext of servlet" + getservletname () +
"' as ServletContext attribute with name [" + attrname + "]");
}
}

Return wac;

Initialize the container if it is already created. Otherwise create the container and create the Logic:

Protected Webapplicationcontext createwebapplicationcontext (applicationcontext parent) {
class<?> Contextclass = Getcontextclass ();
If (this.logger.isDebugEnabled ()) {
this.logger.debug ("Servlet with name '" 027yeshenghuowang.com + Getservletname () +
' would try to create custom Webapplicationcontext context of class ' "+
Contextclass.getname () + "'" + ", using parent context [" + parent + "]");
}
//to Determine if the container is configurable
if (! ConfigurableWebApplicationContext.class.isAssignableFrom (CONTEXTCLASS)) {
throw new Applicationcontextexception (
"Fatal initialization error in Servlets with name '" + getservletname () +
"': Custom W Ebapplicationcontext class ["+ Contextclass.getname () +
"] is not of type Configurablewebapplicationcontext ");
}
//if The target container is found and configurable, then start getting the configuration file and start initializing
Configurablewebapplicationcontext WAC =
( Configurablewebapplicationcontext) Beanutils.instantiateclass (contextclass);

Wac.setenvironment (getenvironment (www.yigouyule2.cn/));
Wac.setparent (parent);
Wac.setconfiglocation (getcontextconfiglocation ());
Here is the portal to get the configuration file and finish initializing the Web container
Configureandrefreshwebapplicationcontext (wac);

Return wac;

This completes the preparation of the Web container and begins the formal reading of the configuration file loading and initializing the Container.

protected void Configureandrefreshwebapplicationcontext (configurablewebapplicationcontext Wac) {
Set an ID for the container
If (objectutils.identitytostring (wac). equals (wac.getid ())) {
The application context ID is still set to its original default value
-assign a more useful ID based on available information
If (this.contextid! = Null) {
Wac.setid (this.contextid);
}
else {
Generate Default ID ...
Wac.setid (configurablewebapplicationcontext.application_context_id_prefix +
Objectutils.getdisplaystring (getservletcontext (). Getcontextpath ()) + '/' + getservletname ());
}
}

Wac.setservletcontext (getservletcontext ());
Wac.setservletconfig (getservletconfig ());
Wac.setnamespace (getnamespace ());
Wac.addapplicationlistener (new sourcefilteringlistener (wac, new Contextrefreshlistener ()));

The WAC environment ' s #initPropertySources'll be called in any case when the context
Is refreshed; Do it eagerly the ensure Servlet property sources is
Use of any post-processing or initialization, occurs below prior to #refresh
Configurableenvironment env = wac.getenvironment ();
If (env instanceof Configurablewebenvironment) {
((configurablewebenvironment) env). initpropertysources (getservletcontext (), getservletconfig ());
}
/* here after the container is activated,
And you can make some changes to the container configuration before the container has finished initializing it.
An empty implementation is given by default,
Subclasses can be rewritten here to get some processing before the container is Initialized.
Postprocesswebapplicationcontext (wac);
This is where the container initialization information is put into a list
Applyinitializers (wac);
Here we begin the initialization of the Web container

Container initialization in abstractapplicationcontext, regardless of the other container, will eventually call to the refresh () function, This function basically defines the entire container initialization of the entire context, here does not expand, this blog should be detailed analysis of this piece of logic, Here's an overview of what each function is doing:

public void refresh () throws beansexception, illegalstateexception {
Synchronized (this.startupshutdownmonitor) {
here, The main load is some variables that are read from other configuration files in the Container.
Preparerefresh ();

Get the container itself
Configurablelistablebeanfactory beanfactory = obtainfreshbeanfactory ();

This completes some of the base component dependencies
Preparebeanfactory (beanfactory);

try {
Pre-processing before adding container initialization
Postprocessbeanfactory (beanfactory);

Call the predecessor processor, which contains Invokebeandefinitionregistrypostprocessors and invokebeanfactorypostprocessors two types of pre-processor calls
Invokebeanfactorypostprocessors (beanfactory);

Pre-processor to register the bean before it is created
Registerbeanpostprocessors (beanfactory);

Initialize the source of the Container's encoding
Initmessagesource ();

Initialize some of the event listeners
Initapplicationeventmulticaster ();

Initialize other special beans in specific context Subclasses.
Onrefresh ();

Registering a container listener
Registerlisteners ();

Initialize all Non-lazy loaded beans
Finishbeanfactoryinitialization (beanfactory);

Last step: Event notification cares about container-loaded related components
Finishrefresh ();
}

Partial code omitted
Since the core container has been loaded and then returned to Framewordservlet's Initwebapplicationcontext function, after calling Createwebapplicationcontext to complete a series of actions above, MVC The servlet component, the entry is the Onrefresh (applocationcontext Context) method. It will call another method initstrategies (applicationcontext context). The method is as Follows:

protected void Initstrategies (applicationcontext Context) {
Initmultipartresolver (context);
Initlocaleresolver (context);
Initthemeresolver (context);
Get all the Requestmappings
Inithandlermappings (context);
Adapters of different Handler
Inithandleradapters (context);
Exception parser
Inithandlerexceptionresolvers (context);
Initrequesttoviewnametranslator (context);
Initviewresolvers (context);
Initflashmapmanager (context);
Here we focus on the inithandlermappings and Inithandleradapters functions, because these are the portals that handle servlet requests.

In spring mvc, any class can handle request requests because Dispacherservlet is also an interface that implements httpservlet, so processing requests is also DOSERVICE. Doservice will hand over the request to the Dodispatcher function for Processing. Then dodispacher the source code:

protected void Dodispatch (httpservletrequest request, httpservletresponse Response) throws Exception {
HttpServletRequest processedrequest = request;
Handlerexecutionchain Mappedhandler = null;
Boolean multipartrequestparsed = false;

Webasyncmanager Asyncmanager = Webasyncutils.getasyncmanager (request);

try {
Modelandview mv = null;
Exception dispatchexception = null;

try {
Processedrequest = Checkmultipart (request);
multipartrequestparsed = (processedrequest! = request);

This gets the processing of the current request handler
Mappedhandler = GetHandler (processedrequest, false);
if (mappedhandler = = NULL | | Mappedhandler.gethandler () = = Null) {
Nohandlerfound (processedrequest, response);
Return
}

/* because handler can be any class,
But our dispacherservlet need a unified processing interface, this interface is handleradapter,
Different handlermapping can be obtained to a variety of handler,
This handler must finally be supported by Handleradapter to be called by Dispacherservlet.
To expand a new handlermapping only need to add a new handleradatper, a bit of abstraction of the factory pattern * *
Handleradapter ha = Gethandleradapter (mappedhandler.gethandler ());

Process last-modified header, If supported by the Handler.
String method = Request.getmethod ();
Boolean isget = "GET". equals (method);
If (isget | | "HEAD". equals (METHOD)) {
Long lastmodified = ha.getlastmodified (request, mappedhandler.gethandler ());
If (logger.isdebugenabled ()) {
Logger.debug ("last-modified value for [" + Getrequesturi (request) + "] is:" + lastmodified);
}
If (new servletwebrequest (request, response). checknotmodified (lastmodified) && Isget) {
Return
}
}

If (!mappedhandler.applyprehandle (processedrequest, Response)) {
Return
}

Actually invoke the Handler.
MV = ha.handle (processedrequest, response, mappedhandler.gethandler ());

If (asyncmanager.isconcurrenthandlingstarted ()) {
Return
}

Applydefaultviewname (request, mv);
Mappedhandler.applyposthandle (processedrequest, response, mv);
}
Catch (Exception ex) {
dispatchexception = ex;
}
Processdispatchresult (processedrequest, response, mappedhandler, mv, dispatchexception);
}
Catch (Exception Ex) {
triggeraftercompletion (processedrequest, response, mappedhandler, ex);
}
Catch (Error err) {
triggeraftercompletionwitherror (processedrequest, response, mappedhandler, err);
}
finally {
if (asyncmanager.isconcurrenthandlingstarted ()) {
//Instead of Posthandle and Aftercompletion
If (mappedhandler! = Null) {
mappedhandler.applyafterconcurrenthandlingstarted (processedrequest, response);
}
}
Else {
//clean up any resources used by a multipart Request.
if (multipartrequestparsed) {
cleanup Multipart (processedrequest);

But we found that the acquired handler is not an object but a handlerexecutionchain, this class can go in to see a bunch of interceptors and a handler, mainly to give each request a pre-processing opportunity, It is worth mentioning that the difference between the interceptor and the filter is that the interceptor can terminate the subsequent execution process, and the filter is generally not terminated. Filters are typically container-level, and this handler pre-interceptor allows finer levels of control, such as filters that define only init and dofilter, But this handler interceptor defines Prehandle and Posthandle as well as Aftercompletion functions, which is not difficult to understand, and is more flexible than the interception granularity corresponding to different request Stages.

Get the GetHandler code that handles Handler:

Protected Handlerexecutionchain gethandler (httpservletrequest Request) throws Exception {
Here you get multiple mapping methods, and once you find the appropriate processing request, handler returns
For (handlermapping Hm:this.handlerMappings) {
If (logger.istraceenabled ()) {
Logger.trace (
"testing Handler Map [" + HM + "] in Dispatcherservlet with name ' + getservletname () +" ' ");
}
The Handlerexecutionchain contains
Handlerexecutionchain handler = Hm.gethandler (request);
If (handler! = Null) {
Return handler;
}
}
Return null;
}
Handleradapter processing returns a uniform encapsulated into an modelandview object, which is the object that contains the attempt and data, after proper processing:

Processdispatchresult (httpservletrequest request, HttpServletResponse response,
Handlerexecutionchain mappedhandler, modelandview mv, Exception Exception)
1
2
1
2
Returns the page and the returned data to the browser to complete the entire request Process. The above is SPRINGMVC about the START process and request processing process, after this blog will continue to analyze the core of spring source, Bo Master has always thought that the famous framework of intensive reading is the shortest time to improve the code capabilities of the shortcut, because these wheels contain too much design ideas and small code specifications, Many of these readings will subtly form an instinctive thing. Design patterns are also constantly running through Them.

SPRINGMVC Container Loading Source analysis

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.