Springmvc as a Struts2 after the emergence of a framework, is becoming more and more popular, I believe that Java EE developers, even if they have not used SPRINGMVC, it should be slightly heard. I try to SPRINGMVC design ideas and the implementation of the source of the analysis, from the abstract sense of design and implementation of the meaning of the code level of two aspects, each to uncover the springmvc mysterious veil, the code of this article is based on the spring 3.1.3RELEASE version.
Any framework has its own specific areas of application, and the design and implementation of the framework must be designed to cope with many common, cumbersome, and basic work in the field. As a presentation framework, SPRINGMVC must also confront several major issues in the field of web development and give its own answers:
URL-to-frame mapping.
HTTP request Parameter Binding
Generation and output of HTTP responses
These three major topics, the formation of a complete Web request flow, each part has a very broad extension. What is the SPRINGMVC framework's answer to these questions?
The first thing to learn about a framework is to first understand its design ideas. Look at this framework from an abstract, holistic perspective. One of the most valuable references is the core interface defined by this framework. The core interface defines the skeleton of the frame, and in the most abstract sense expresses the design idea of the frame.
Here I take a Web request process as a carrier, in turn, introduce the core interface and class SPRINGMVC.
The user enters the address of the HTTP://WWW.XXXX.COM/AAA/BBB.CCC in the browser, and after the carriage return, the browser initiates an HTTP request. After the request arrives at your server, The first is received by SPRINGMVC, the front-end forwarder Dispatcherservlet registered in Web. XML, Dispatcherservlet is a standard servlet whose role is to accept and forward Web requests to the internal framework processing unit.
Take a look at the first core interface that appears in front of you, which is the Handlermapping interface defined in the Org.springframework.web.servlet package:
Package org.springframework.web.servlet;
Import Javax.servlet.http.HttpServletRequest;
Public interface Handlermapping {
String Path_within_handler_mapping_attribute = HandlerMapping.class.getName () + ". Pathwithinhandlermapping";
String Best_matching_pattern_attribute = HandlerMapping.class.getName () + ". Bestmatchingpattern";
String introspect_type_level_mapping = HandlerMapping.class.getName () + ". Introspecttypelevelmapping";
String Uri_template_variables_attribute = HandlerMapping.class.getName () + ". Uritemplatevariables";
String Producible_media_types_attribute = HandlerMapping.class.getName () + ". Produciblemediatypes";
Handlerexecutionchain GetHandler (HttpServletRequest request) throws Exception;
}
For readability, I removed the comments from the source code, but I strongly recommend that you remember to read it so that you can get the most accurate design instructions for this class or interface from the designer of the framework. A few constants defined in the class, we do not control it first. The key is the only method in this interface:
Handlerexecutionchain GetHandler (HttpServletRequest request) throws Exception;
This method, even for a Java beginner, is easy to understand: It has only one parameter of type HttpServletRequest, throws exception declares that it does not handle any type of exception, The Handlerexecutionchain is its return type.
Back to the Dispatcherservlet process, when Dispatcherservlet received a Web request, the standard Servlet class processing method doget or Dopost, after several forwards, A list of handlermapping implementation classes that are eventually registered in the Dispatcherservlet class (a bit of a mouthful) is traversed in a loop. The HttpServletRequest object for the Web request is a parameter, and then its GetHandler method is called, and the first non-null call result is returned. Dispatcherservlet class of this traversal method is not long, paste it, so that everyone has a more intuitive understanding.
/**
* Return The Handlerexecutionchain for this request.
* <p>tries All handler mappings in order.
* @param request Current HTTP request
* @return The Handlerexecutionchain, or <code>null</code> if no handler could be found
*/
Protected Handlerexecutionchain GetHandler (HttpServletRequest request) throws Exception {
for (handlermapping hm:this.handlerMappings) {
if (logger.istraceenabled ()) {
Logger.trace (
"Testing handler Map [" + HM + "] in Dispatcherservlet with Name ' + getservletname () +" ' ");
}
Handlerexecutionchain handler = Hm.gethandler (request);
if (handler! = null) {
return handler;
}
}
return null;
}
Yes, the first step is as simple as done. Once a Web request has been processed, a Handlerexecutionchain object is obtained, which is the answer SPRINGMVC to the URL mapping. It should be noted that the GetHandler method parameter of the Handlermapping interface is httpservletrequest, which means that the Handlermapping implementation class can take advantage of the HttpServletRequest All information to make a "decision" on the generation of this Handlerexecutionchain object. This includes the request header, URL path, cookie, session, parameters and everything you can get from a Web request (most commonly URL path).
The first extension point of SPIRNGMVC, which appears here. We can write arbitrary handlermapping implementation classes that determine the generation of a Web request to a Handlerexecutionchain object based on any policy. It can be said that, starting from the declaration of the first core interface, SPRINGMVC the flexibility and ambition of his own: "Open-closed" is what the elder brother is playing.
Handlerexecutionchain This class is the next core class that we want to understand. From the name it can be intuitively seen that this object is an execution chain of encapsulation. Familiar with the Struts2 know that the action object is also a layer of interceptor packaging, here can make an analogy, that SPRINGMVC is really absorbed Struts2 part of the design ideas.
Handlerexecutionchain class code is not long, it is defined in the Org.springframework.web.servlet package, in order to more intuitive understanding, first on the code.
Package org.springframework.web.servlet;
Import java.util.ArrayList;
Import Java.util.Arrays;
Import java.util.List;
Import Org.springframework.util.CollectionUtils;
public class Handlerexecutionchain {
Private final Object handler;
Private handlerinterceptor[] interceptors;
Private list
Public Handlerexecutionchain (Object handler) {
This (handler, NULL);
}
Public Handlerexecutionchain (Object handler, handlerinterceptor[] interceptors) {
if (handler instanceof Handlerexecutionchain) {
Handlerexecutionchain Originalchain = (handlerexecutionchain) handler;
This.handler = Originalchain.gethandler ();
This.interceptorlist = new arraylistCollectionutils.mergearrayintocollection (Originalchain.getinterceptors (), this.interceptorlist);
Collectionutils.mergearrayintocollection (interceptors, this.interceptorlist);
}
else {
This.handler = handler;
This.interceptors = interceptors;
}
}
Public Object GetHandler () {
return this.handler;
}
public void Addinterceptor (Handlerinterceptor Interceptor) {
Initinterceptorlist ();
This.interceptorList.add (Interceptor);
}
public void Addinterceptors (handlerinterceptor[] interceptors) {
if (interceptors! = null) {
Initinterceptorlist ();
This.interceptorList.addAll (Arrays.aslist (interceptors));
}
}
private void Initinterceptorlist () {
if (this.interceptorlist = = null) {
This.interceptorlist = new arraylist}
if (this.interceptors! = null) {
This.interceptorList.addAll (Arrays.aslist (this.interceptors));
This.interceptors = null;
}
}
Public handlerinterceptor[] Getinterceptors () {
if (this.interceptors = = NULL && this.interceptorlist! = null) {
This.interceptors = This.interceptorList.toArray (New Handlerinterceptor[this.interceptorlist.size ()]);
}
return this.interceptors;
}
@Override
Public String toString () {
if (This.handler = = null) {
Return "Handlerexecutionchain with no handler";
}
StringBuilder sb = new StringBuilder ();
Sb.append ("Handlerexecutionchain with Handler ["). Append (This.handler). Append ("]");
if (! Collectionutils.isempty (this.interceptorlist)) {
Sb.append ("and"). Append (This.interceptorList.size ()). Append ("Interceptor");
if (This.interceptorList.size () > 1) {
Sb.append ("s");
}
}
return sb.tostring ();
}
}
A lot of mess, I believe you have not read it all, there is no need to look. In fact, we just need to look at two lines.
Private final Object handler;
Private handlerinterceptor[] interceptors;
Not what we expected, a real object of execution, and a bunch of interceptors. This is not the implementation of STRUTS2, SPRINGMVC no suspicion, or the use of this package. After getting handlerexecutionchain This execution chain (execution chain), the next process will be expanded around it.
Handlerinterceptor is also the core interface of SPRINGMVC, as defined below:
Package org.springframework.web.servlet;
Import Javax.servlet.http.HttpServletRequest;
Import Javax.servlet.http.HttpServletResponse;
Public interface Handlerinterceptor {
Boolean Prehandle (HttpServletRequest request, httpservletresponse response, Object handler)
Throws Exception;
void Posthandle (
HttpServletRequest request, HttpServletResponse response, Object handler, Modelandview Modelandview)
Throws Exception;
void Aftercompletion (
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
Throws Exception;
}
At this point, the entire execution of the Handlerexecutionchain is clear: before actually invoking its handler object, an array of Handlerinterceptor interface implementation classes will be traversed, and the Prehandle method will be called sequentially. Then the real handler object will be called.
When the handler object is called, the required response data is generated, and the Posthandle method is called sequentially before the processing result is written to the HttpServletResponse object (Springmvc is called the rendered view). When the view rendering is complete, the last Aftercompletion method is called sequentially, and the entire Web request process is finished.
Before the execution of a processing object, the use of interceptors, which has become a classic framework design routines. Interceptors in Struts2 do complex tasks such as parameter binding, so what does the SPRINGMVC interceptor specifically do? We do not care for the moment, although this is a very important detail, but the details are the details, we first to understand the more important things.
Handlerinterceptor, is the exposure of the second extension point of Springmvc, through a custom interceptor, we can be processed before a request is actually processed, but not yet output to the response, The request has been output to the response after these three points of time to do anything we want to do. The success of the STRUTS2 framework stems from the design of the interceptor, which SPRINGMVC absorbed the design idea and introduced a more reasonable division of three different time points, thus providing greater extensibility for the Web request to process the process.
What exactly is a handler object declared in this Handlerexecutionchain class as an object? How is it called?
Before answering these questions, let's look at another core interface in Springmvc, Handleradapter:
Package org.springframework.web.servlet;
Import Javax.servlet.http.HttpServletRequest;
Import Javax.servlet.http.HttpServletResponse;
Public interface Handleradapter {
Boolean supports (Object handler);
Modelandview handle (HttpServletRequest request, httpservletresponse response, Object handler) throws Exception;
Long getlastmodified (httpservletrequest request, Object handler);
}
In Dispatcherservlet, in addition to the list of handlermapping implementation classes, a list of Handleradapter implementation classes is also registered, with the code as proof.
/** List of handlermappings used by this servlet */
Private list
/** List of handleradapters used by this servlet */
Private listNext, we will answer the above questions in another section of the Dispatcherservlet class:
/**
* Return The Handleradapter for this handler object.
* @param handler The handler object to find a adapter for
* @throws servletexception If no handleradapter can be found for the handler. This is a fatal error.
*/
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 +
"]: Does your handler implement a supported interface like Controller?");
}
This code is already obvious, the handler object in Handlerexecutionchain is passed as a parameter, and the list of Handleradapter implementation classes registered in the Dispatcherservlet class is traversed. The first supports method returns the true Handleradapter object, and the handler object is processed with the handle method in the Handleradapter implementation class. and returns Modelandview, the object that contains the view and data. Handleradapter is the third extension point provided by SPRINGMVC, and you can provide your own implementation class to handle handler objects.
The code for the Modelandview object is not affixed, it is an aggregation class for the view and data in SPRINGMVC. The view is abstracted from the last core interface view of SPRINGMVC:
Package org.springframework.web.servlet;
Import Java.util.Map;
Import Javax.servlet.http.HttpServletRequest;
Import Javax.servlet.http.HttpServletResponse;
Public interface View {
String Response_status_attribute = View.class.getName () + ". ResponseStatus";
String path_variables = View.class.getName () + ". Pathvariables";
String getContentType ();
void Render (map<string,?> model, httpservletrequest request, httpservletresponse response) throws Exception;
}
All of the data, which is then passed to the Render method in the view implementation class as a map object, calls the Render method and completes the view-to-response rendering. The View implementation class is the result of the return of the handle method from Handleradapter. Of course, from Modelandview to the real view implementation class has a parsing process, Modelandview can have a real view object, or can just have a view of the name, SPRINGMVC will be responsible for the view name resolution to the real view object.
At this point, we understand the process of a typical complete Web request in SPRINGMVC and the core classes and interfaces involved.
In a typical SPRINGMVC call, the encapsulated handler object in Handlerexecutionchain is an instance of the class identified with the @controller annotation, based on the @requestmapping annotations at the class level and method level, The defaultannotationhandlermapping (3.1.3), which is registered by default, is updated to the Requestmappinghandlermapping class, but for backwards compatibility, defaultannotationhandlermapping can also make The Handlerexecutionchain object is generated using the The Requestmappinghandleradapter class is then updated by Annotationmethodhandleradapter (3.1.3), but for backwards compatibility, annotationmethodhandleradapter can also be used to perform this A Handlerexecutionchain object that generates the final Modelandview object and then renders the view by the Render method of the specific view object.
It can be seen that as a presentation framework, SPRINGMVC is not as radical as Struts2, and does not adopt a completely decoupled design idea from the Web container, but relies on the native Servlet framework object and formulates a rigorous process flow through reasonable abstraction. As a result, the efficiency of execution is higher than Struts2, and flexibility has risen to a level.
Original Digest from https://my.oschina.net/lichhao/blog/99039
SPRINGMVC Excellent source parsing (a)-from abstraction and interface