In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces the SpringMVC design concept and DispatcherServlet example analysis, the article introduces in great detail, has a certain reference value, interested friends must read it!
Introduction to SpringMVC
As a presentation framework after Struts2, SpringMVC is becoming more and more popular. It is believed that developers of javaee should have heard of SpringMVC even if they have not used it. Through the analysis of the design idea and source code implementation of SpringMVC, I try to unveil the mystery of SpringMVC one by one from the design level in the abstract sense and the code level in the implementation sense. The code of this paper is based on the 3.1.3RELEASE version of Spring.
Any framework has its own specific field of application, and the design and implementation of the framework must be to cope with many general, tedious and basic work in this field. As a presentation framework, SpringMVC must also face several major issues in the presentation layer in the field of Web development, and give its own answers:
URL to framework mapping.
Http request parameter binding
Generation and output of http response
These three topics constitute a complete web request process, and each part has a very broad extension. What is the answer of the SpringMVC framework to these questions?
To learn a framework, the first thing is to understand its design ideas. Look at the framework from an abstract and global perspective. One of the most valuable is the core interface defined by this framework. The core interface not only defines the framework of the framework, but also expresses the design idea of the framework in the most abstract sense.
Next, I will introduce the core interfaces and classes of SpringMVC in turn, using a web request process as the carrier.
The user enters the address of http://www.xxxx.com/aaa/bbb.ccc in the browser, and after entering enter, the browser initiates a http request. When a request arrives at your server, it is first received by DispatcherServlet, a front-end forwarder registered by SpringMVC in web.xml. DispatcherServlet is a standard Servlet that accepts and forwards web requests to the internal framework processing unit.
HandlerMapping interface
Let's 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;}
I have removed the comments from the source code for ease of reading, but I strongly recommend that you remember to read it so that you can get the most accurate description of the design of this class or interface from the designer of the framework. Class, let's leave it alone. The key is the only method in this interface:
HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception
This method is easy to understand even for a beginner of java: it has only one parameter of type HttpServletRequest, throws Exception's declaration indicates that it does not handle any type of exception, and HandlerExecutionChain is its return type.
DispatcherServlet accepts the request and finds the corresponding Handler
Back to the DispatcherServlet process, when DispatcherServlet receives the web request, the standard Servlet class processing method doGet or doPost, after several forwards, a List (a bit of a mouthful) made up of the HandlerMapping implementation class eventually registered in the DispatcherServlet class is traversed in a loop. Take the HttpServletRequest object of the web request as a parameter, call its getHandler method in turn, and the first call result that is not null will be returned. The traversal method in the DispatcherServlet class is not long. Post it to give you a more intuitive understanding.
/ * Return the HandlerExecutionChain for this request. *
Tries all handler mappings in order. * @ param request current HTTP request * @ return the HandlerExecutionChain Or null 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 that. After a web request is processed, you get a HandlerExecutionChain object, which is SpringMVC's answer to the URl mapping. It is important to note that the getHandler method parameter of the HandlerMapping interface is HttpServletRequest, which means that the implementation class of HandlerMapping can use all the information in HttpServletRequest to make "decisions" on the generation of this HandlerExecutionChain object. This includes request headers, url paths, cookie, session, parameters, and so on, anything you can get from a web request (the most common is the url path).
This is where the first extension point of SpirngMVC appears. We can write any HandlerMapping implementation class, according to any policy to determine the generation of a web request to the HandlerExecutionChain object. It can be said that since the declaration of the first core interface, SpringMVC has exposed its flexibility and ambition: I am playing "Open-Closed".
The HandlerExecutionChain class is the next core class we will learn about. It can be seen visually from the name that this object is an encapsulation of an execution chain. Those who are familiar with Struts2 know that Action objects are also wrapped by layer-by-layer interceptors, and here you can make an analogy to show that SpringMVC really absorbs some of the design ideas of Struts2.
The code for the HandlerExecutionChain class is not long, it is defined in the org.springframework.web.servlet package, and for a more intuitive understanding, code first.
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 interceptorList; 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 ArrayList (); CollectionUtils.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 ();}}
It's a mess. I'm sure you haven't read it all, and you don't have to read it all. In fact, you only need to look at two lines.
Private final Object handler; private HandlerInterceptor [] interceptors
As we expected, an actual execution object and a bunch of interceptors. This is not the implementation of Struts2, SpringMVC did not avoid suspicion, or adopted this kind of encapsulation. Once you get the execution chain (execution chain) of HandlerExecutionChain, the next step of processing will revolve around it.
HandlerInterceptor interface
HandlerInterceptor is also the core interface of SpringMVC. It is defined as follows:
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 context of HandlerExecutionChain is clear: before actually calling its handler object, the array of HandlerInterceptor interface implementation classes will be traversed, its preHandle method will be called in turn, and then the real handler object will be called.
After the handler object is called, the required response data is generated, and before the processing result is written to the HttpServletResponse object (SpringMVC is called render View), its postHandle method is called in turn. After the view rendering is completed, the afterCompletion method is called in turn, and the entire processing of the web request is finished.
The use of interceptors before and after the execution of a processing object has become a classic framework design routine. Interceptors in Struts2 do complex tasks such as parameter binding, so what exactly does SpringMVC interceptors do? We do not care for the time being, although this is a very important detail, but the details are after all details, let's first understand the more important things.
HandlerInterceptor, the second extension point of SpringMVC, is exposed. With custom interceptors, we can do anything we want before a request is actually processed, after the request is processed but not yet output to the response, and after the request has been output to the response. The success of the Struts2 framework stems from the design of this interceptor. SpringMVC absorbs this design idea, pushes out the old and brings forth the new, and divides three different time points more reasonably, thus providing greater expansibility for the process of web request processing.
What exactly is the handler object declared with an Object reference in this HandlerExecutionChain class? How is it called?
HandlerAdapter
Before answering these questions, let's take a 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, as evidenced by the code.
/ * * List of HandlerMappings used by this servlet * / private List handlerMappings; / * * List of HandlerAdapters used by this servlet * / private List handlerAdapters
Next, we answer the above question with another piece of code in the DispatcherServlet class:
/ * Return the HandlerAdapter for this handler object. * @ param handler the handler object to find an 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?") } request process summary
This code is already clear that the handler object in HandlerExecutionChain will be passed as a parameter, the list of HandlerAdapter implementation classes registered in the DispatcherServlet class will be traversed, and then the first supports method will return the HandlerAdapter object of true, using the handle method in this HandlerAdapter implementation class to process the handler object and return ModelAndView, which contains the view and data. HandlerAdapter is the third extension point provided by SpringMVC, and you can provide your own implementation classes to handle handler objects.
The code for the ModelAndView object is not pasted, it is an aggregation class for views and data in SpringMVC. The view is abstracted by View, the last core interface 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 model, HttpServletRequest request, HttpServletResponse response) throws Exception;}
All the data is finally passed as a Map object to the render method in the View implementation class, and the render method is called to complete the view-to-response rendering. This View implementation class is the result returned from the handle method in HandlerAdapter. Of course, there is a parsing process from the ModelAndView to the real View implementation class. There can be a real view object or just a view name in the ModelAndView. SpringMVC will be responsible for parsing the view name to the real view object.
So far, we have learned how a typical complete web request is processed in SpringMVC and the core classes and interfaces involved.
In a typical SpringMVC call, encapsulating the handler object in HandlerExecutionChain is an instance of the class identified with the @ Controller annotation. According to the @ RequestMapping annotation at the class level and method level, the default registered DefaultAnnotationHandlerMapping (updated to RequestMappingHandlerMapping class in 3.1.3, but DefaultAnnotationHandlerMapping can also be used for backward compatibility) generates a HandlerExecutionChain object, and then AnnotationMethodHandlerAdapter (3.1.3 to RequestMappingHandlerAdapter class, but for backward compatibility) AnnotationMethodHandlerAdapter can also use) to execute the HandlerExecutionChain object, generate the final ModelAndView object, and then render the view by the render method of the specific View object.
As we can see, as a presentation layer framework, SpringMVC is not as radical as Struts2, and does not adopt the design idea of complete decoupling from the Web container, but relies on the native Servlet framework object and formulates a rigorous processing flow through reasonable abstraction. As a result, execution is more efficient than Struts2, and flexibility rises to a higher level.
The above is all the content of the article "SpringMVC Design concept and sample Analysis of DispatcherServlet". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.