In the previous analysis of Dispatcherservlet, how to deal with the request after the beginning, this article will focus on the analysis, handlermapping and handleradapter how to work
In the process of launching the Web container, the classes required for a series of SPRINGMVC are initially initialized, and here we look at the Inithandlermethods method of the Abstracthandlermethodmapping class.
If the bean has the corresponding annotation detection handlermethod
Concrete look at the implementation of Selectmethods method
And the inspect method calls the Getmappingformethod method to implement the implementation by its subclass requestmappinghandlermapping
Protected Requestmappinginfo Getmappingformethod (method, class<?> handlertype) {
requestmappinginfo Info = Createrequestmappinginfo (method);
if (info! = null) {
Requestmappinginfo typeinfo = Createrequestmappinginfo (handlertype);
if (typeinfo! = null) {
info = typeinfo.combine (info);}
}
return info;
}
This method returns an instance of the Requestmappinginfo class, which shows that the T type in our previous methods map is Requestmappinginfo
This class is a class that encapsulates the various request-mapping criteria and implements the Requestcondition interface. There are various Requestcondition implementation class properties, Patternscondition,methodscondition,paramscondition,headerscondition, Consumescondition and Producescondition, please.
The condition depends on the property name, which represents the path pattern, method, parameter, and header of the HTTP request, respectively.
Continue to see the Getmappingformethod method, the specific implementation of Createrequestmappinginfo is as follows:
Private Requestmappinginfo Createrequestmappinginfo (annotatedelement Element) {
requestmapping requestmapping = Annotatedelementutils.findmergedannotation (element, requestmapping.class);
requestcondition<?> condition = (element instanceof class<?>?
) Getcustomtypecondition ((class<?>) Element): Getcustommethodcondition (Method) element);
Return (requestmapping! = null? createrequestmappinginfo (requestmapping, condition): null);
}
First find the @requestmapping annotation of the method, then get requestcondition, if there is an annotation, call the concrete creation method, otherwise return null
Protected Requestmappinginfo createrequestmappinginfo (
requestmapping requestmapping, requestcondition<? > customcondition) {
return requestmappinginfo
. Paths (Resolveembeddedvaluesinpatterns ( Requestmapping.path ()))
. Methods (Requestmapping.method ()).
params (Requestmapping.params ())
. Headers (requestmapping.headers ())
. Consumes (Requestmapping.consumes ())
. produces ( Requestmapping.produces ())
. MappingName (Requestmapping.name ()).
customcondition (customcondition)
. Options (This.config)
. Build ();
}
In addition to pathcondithion others are directly using the condition in the requestmapping annotation
Look back and see the Registerhandlermethod method
The URL-related operations are registered to this end
Look back. The call to GetHandler in the Dodispatch method will eventually call the Gethandlerinternal method, specifically:
Protected Handlermethod gethandlerinternal (HttpServletRequest request) throws Exception {
String Lookuppath = Geturlpathhelper (). Getlookuppathforrequest (request);
if (logger.isdebugenabled ()) {
logger.debug ("Looking up handler method for path" + Lookuppath);
}
This.mappingRegistry.acquireReadLock ();
try {
Handlermethod Handlermethod = Lookuphandlermethod (Lookuppath, request);
if (logger.isdebugenabled ()) {
if (handlermethod! = null) {
Logger.debug ("Returning handler method [" + Handlerme Thod + "]");
}
else {
Logger.debug ("Didn't not find handler method for [" + Lookuppath + "]");
}
}
Return (Handlermethod! = null? Handlermethod.createwithresolvedbean (): null);
}
finally {
this.mappingRegistry.releaseReadLock ();
}
}
The key code is to get Handlermethod by calling Lookuphandlermethod
The above is based on the controller method of mapping requestmappinghandlermapping, about the static resource mapping here is not to be described in detail, the corresponding handlermpping is simpleurlhandlermapping
Handlerexecutionchain Executionchain = Gethandlerexecutionchain (handler, request);
Build Handlerexecutionchain with Handler and request
Protected Handlerexecutionchain Gethandlerexecutionchain (Object handler, HttpServletRequest request) {
Handlerexecutionchain chain = (Handler instanceof handlerexecutionchain?
) (Handlerexecutionchain) Handler:new Handlerexecutionchain (handler));
String Lookuppath = this.urlPathHelper.getLookupPathForRequest (request);
for (Handlerinterceptor interceptor:this.adaptedInterceptors) {
if (Interceptor instanceof Mappedinterceptor) { C5/>mappedinterceptor mappedinterceptor = (mappedinterceptor) interceptor;
if (Mappedinterceptor.matches (Lookuppath, This.pathmatcher)) {
Chain.addinterceptor ( Mappedinterceptor.getinterceptor ());
}
}
else {
chain.addinterceptor (Interceptor);
}
}
return chain;
}
handleradapter Access and how it works
Also in Dodispatch we get handleradapter through handler.
Handleradapter ha = Gethandleradapter (Mappedhandler.gethandler ());
Protected Handleradapter Gethandleradapter (Object handler) throws Servletexception {for
(Handleradapter ha: This.handleradapters) {
if (logger.istraceenabled ()) {
Logger.trace ("Testing handler adapter [" + Ha + "]");
}
if (Ha.supports (handler)) {
return ha;
}
}
throw new Servletexception ("No Adapter for Handler [" + Handler +
"]: the Dispatcherservlet configuration needs Clude a handleradapter that supports this handler ");
}
The handleradapters used here is initialized in the private void Inithandleradapters (ApplicationContext context) method, The general idea is to find all instances of the class that implement the Handleradapter interface and put it in the list.
We use the Requestmappinghandleradapter instance to analyze the corresponding supports method as the parent class Abstracthandlermethodadapter method:
Public Final Boolean supports (Object handler) {
return (handler instanceof Handlermethod && supportsinternal ((Handlermethod) handler));
}
Implement Supportsinternal in Requestmappinghandleradapter:
Protected Boolean supportsinternal (Handlermethod handlermethod) {
return true;
}
You can see that Requestmappinghandleradapter is an adaptation call to all Handlermethod
Back to Dodispatch
MV = Ha.handle (processedrequest, Response, Mappedhandler.gethandler ());
The implementation of the handler call core method Handleinternal is:
Protected Modelandview handleinternal (httpservletrequest request,
httpservletresponse response, Handlermethod Handlermethod) throws Exception {
checkrequest (request);
if (Getsessionattributeshandler (Handlermethod). Hassessionattributes ()) {
Applycacheseconds (response, this.cachesecondsforsessionattributehandlers);
}
else {
prepareresponse (response);
}
Execute Invokehandlermethod in synchronized block if required.
if (this.synchronizeonsession) {
HttpSession session = Request.getsession (false);
if (session! = null) {
Object mutex = Webutils.getsessionmutex (session);
Synchronized (mutex) {
return Invokehandlermethod (Request, response, Handlermethod);
}} return Invokehandlermethod (Request, response, Handlermethod);
}
A lot of content, we just need to focus on Invokehandlermethod
Protected Modelandview Invokehandlermethod (httpservletrequest request, httpservletresponse response, Handlermethod
Handlermethod) throws Exception {servletwebrequest webRequest = new Servletwebrequest (request, response);
Webdatabinderfactory binderfactory = getdatabinderfactory (Handlermethod);
Modelfactory modelfactory = Getmodelfactory (Handlermethod, binderfactory);
Servletinvocablehandlermethod Invocablemethod = Createinvocablehandlermethod (Handlermethod);
Invocablemethod.sethandlermethodargumentresolvers (this.argumentresolvers);
Invocablemethod.sethandlermethodreturnvaluehandlers (this.returnvaluehandlers);
Invocablemethod.setdatabinderfactory (binderfactory);
Invocablemethod.setparameternamediscoverer (This.parameternamediscoverer);
Modelandviewcontainer Mavcontainer = new Modelandviewcontainer ();
Mavcontainer.addallattributes (Requestcontextutils.getinputflashmap (request));
Modelfactory.initmodel (WebRequest, Mavcontainer, Invocablemethod); Mavcontainer.Setignoredefaultmodelonredirect (This.ignoredefaultmodelonredirect);
Asyncwebrequest asyncwebrequest = webasyncutils.createasyncwebrequest (request, response);
Asyncwebrequest.settimeout (this.asyncrequesttimeout);
Webasyncmanager Asyncmanager = Webasyncutils.getasyncmanager (request);
Asyncmanager.settaskexecutor (This.taskexecutor);
Asyncmanager.setasyncwebrequest (asyncwebrequest);
Asyncmanager.registercallableinterceptors (this.callableinterceptors);
Asyncmanager.registerdeferredresultinterceptors (this.deferredresultinterceptors);
if (Asyncmanager.hasconcurrentresult ()) {Object result = Asyncmanager.getconcurrentresult ();
Mavcontainer = (Modelandviewcontainer) asyncmanager.getconcurrentresultcontext () [0];
Asyncmanager.clearconcurrentresult ();
if (logger.isdebugenabled ()) {Logger.debug ("Found Concurrent result value [" + Result + "]");
} Invocablemethod = Invocablemethod.wrapconcurrentresult (result); } invocablemethod.invokeandhandle (WebrequeSt, Mavcontainer);
if (asyncmanager.isconcurrenthandlingstarted ()) {return null;
} return Getmodelandview (Mavcontainer, Modelfactory, webRequest);
}
In this method, the Servletinvocablehandlermethod object is created according to Handlermethod, and the corresponding Resovler is set during the execution of the method.
Then call Invokeandhandle:
public void Invokeandhandle (Servletwebrequest webRequest, Modelandviewcontainer Mavcontainer, Object ... Providedargs) throws Exception {//Execute request and return result Object returnvalue = Invokeforrequest (webrequ
EST, mavcontainer, Providedargs);
Setresponsestatus (webRequest); if (returnvalue = = null) {if (isrequestnotmodified (webRequest) | | | hasresponsestatus () | | mavcontainer.isrequesthandled
()) {mavcontainer.setrequesthandled (true);
Return
}} else if (Stringutils.hastext (This.responsereason)) {mavcontainer.setrequesthandled (true);
Return
} mavcontainer.setrequesthandled (FALSE); try {this.returnValueHandlers.handleReturnValue (returnvalue, Getreturnvaluetype (returnvalue), Mavcontainer, WEBR
Equest); } catch (Exception ex) {if (logger.istraceenabled ()) {Logger.trace (Getreturnvaluehandlingerrormessage ("Error ha
ndling return value ", returnvalue), ex);
} throw ex; }
}
You can see that the first line calls Invokeforrequest execution request
public Object Invokeforrequest (nativewebrequest request, Modelandviewcontainer Mavcontainer,
object ... Providedargs) throws Exception {
object[] args = getmethodargumentvalues (Request, Mavcontainer, Providedargs);
if (logger.istraceenabled ()) {
logger.trace ("invoking" + Classutils.getqualifiedmethodname (GetMethod (), Getbeantype ()) +
"' with arguments" + arrays.tostring (args);
}
Object returnvalue = Doinvoke (args);
if (logger.istraceenabled ()) {
logger.trace ("Method [" + Classutils.getqualifiedmethodname (GetMethod (), Getbeantype ()) +
"] returned [" + ReturnValue + "]");
return returnvalue;
}
Continue with the Doinvoke method, for the above request parameter parsing the next blog will be analyzed, this article only analysis method call
Among the Getbridgedmethod are:
Protected Method Getbridgedmethod () {
return this.bridgedmethod;
}
And our bridgedmethod is what, do not know that everyone has noticed, in the previous I mentioned the creation of Servletinvocablehandlermethod instance
Servletinvocablehandlermethod Invocablemethod = Createinvocablehandlermethod (Handlermethod);
The Createinvocablehandlermethod is a good call to the Servletinvocablehandlermethod Handlermethod parameter constructor, and will eventually call the Handlermethod constructor:
Protected Handlermethod (Handlermethod handlermethod) {
assert.notnull (Handlermethod, "Handlermethod is required" );
This.bean = Handlermethod.bean;
This.beanfactory = handlermethod.beanfactory;
This.beantype = Handlermethod.beantype;
This.method = Handlermethod.method;
This.bridgedmethod = Handlermethod.bridgedmethod;
This.parameters = handlermethod.parameters;
This.responsestatus = Handlermethod.responsestatus;
This.responsestatusreason = Handlermethod.responsestatusreason;
This.resolvedfromhandlermethod = Handlermethod.resolvedfromhandlermethod;
}
There is the assignment of Bridgedmethod, and it should be clear how adapter is calling our controller.
This section focuses on the working principles and processes of requestmappinghandlermapping and requestmappinghandleradapter.