What is your first impression of Spring MVC? A lightweight framework to simplify Web development? In fact, in the modern development process, the continuous improvement of development process and development efficiency, along with the rise of the combination of Restful and Json, makes cross-platform call and access of multiple devices much easier, so the mission of Spring MVC to simplify Web development has naturally changed to simplify server-side development. So today we’ll take a look at the big picture of how Spring MVC implements a solution for handling requests and simplifying server-side development.
1. The old king — Servlet
When I first came into contact with Java for Web development, Spring MVC was far less popular than it is today, and servlets, the former king, were flourishing at that time. In retrospect, although it is not as easy to develop with Servlet as it is now, many things need to be done by yourself, but Servlet makes the logic of development very clear, especially after Servlet and JSP well assume their respective roles, coupled with the popularity of MVC layering. Writing Web applications was fun and easy.
In fact, servlets don’t do much, and I think what servlets want to do is unify the flow of receiving, processing, and responding to requests.
Network programming around an east east must not have to say that we also guess, that is Socket. But network transmission is very complex, the first need to follow a certain protocol, now we generally use Http and Https data transmission, and Socket is on some network protocols, shielding the details of the underlying protocol, to provide a unified API for users. But the Servlet thinks that Socket is not doing enough, or that we need to deal with it accordingly. So servlets (in the case of Httpservlets) encapsulate requests from the network into a Request representation, which in Http communication is HttpServletRequest, The unified encapsulation of the response returned by the server after processing the request is an HttpServletResponse object.
What are the benefits of this?
We, as developers, don’t have to do the tedious work of handling network requests and responses, and just focus on developing our business logic.
Have you found that every improvement in the efficiency of the framework is to completely separate the most important business logic from other tasks as far as possible, so that we can always devote ourselves to the development of business logic, Spring AOP is not a good evidence of it!
So how do servlets work?
For those of you who have no experience with servlets, let me briefly explain:
- We usually start by writing our own Servlet that inherits from HttpServlet and overrides its doGet() and doPost() methods. Both methods pass in HttpServletRequest and HttpServletResponse as arguments. Then we extract the parameters from the Request and invoke the pre-written Service interface in the corresponding doXXX method. The Dao interface can simply place the data ready in Response and jump to the specified page. The way of jump can be forwarding or redirection.
- The Servlet uses the template method design pattern, and at the top of the Servlet will call the Service method, which constructs an HttpServletRequest and an HttpServletResponse object as arguments to call the subclass override doXXX() method. Then return the request.
- Finally, we need to register the custom Servlet we wrote with web.xml and configure servlet-Mapping in web.xml to specify which requests the Servlet will handle.
That’s how easy it is to use servlets! In fact, its popularity over a long period of time also benefits from its ease of use.
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>ShoppingServlet</servlet-name>
<servlet-class>com.myTest.ShoppingServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ShoppingServlet</servlet-name>
<url-pattern>/shop/ShoppingServlet</url-pattern>
</servlet-mapping>
</web-app>
Copy the code
2. Want to take things further
When we use servlets for business logic development, we often feel great, but at the same time feel a little uncomfortable. Discomfort mainly has the following points:
- Each Servlet can only handle one request, so when the system is large and the business is complex, there may be hundreds of servlets, which can be confusing to find.
- Each time we need to manually obtain the Request parameters from the Request, and then encapsulate them into the object we want, which may require verification of the parameters. After the data is obtained by calling the business logic layer, we need to manually set the parameters into the response, and manually select forwarding or redirection to redirect.
- The URL of our request is hardwired into web.xml and lacks flexibility. It would be nice if we could dynamically configure the mapping between the request URL and the processing.
- Our Servlet is tightly coupled to the rendering framework at the front end, so that the current end will need to change a lot of code when switching to a different display technology. It would be better if we could decoupled the processing of the data from the display of the data, allowing it to be loosely coupled.
With these thoughts in mind, can we move further away from business logic development?
In the early days, THE author also made some attempts. The general idea was to write a BaseServlet, and then we defined our own Servlet inherited from BaseServlet. The front-end request needed to specify which method of the Servlet to handle, so that the request would need to take a method parameter. For example:
http://localhost:8080/myProject/MyServlet? method=getInfo
Copy the code
The BaseServlet extracts this parameter information and calls the method of the subclass using the reflected method. The subclass method returns a result of type String, representing the name of the logical view to return, that is, the path to jump to. The parent class then gets the result and redirects or forwards the jump.
I haven’t seen anything about Spring MVC yet. It’s all about servlets. Before you worry, understanding this will help us a lot in understanding Spring MVC. Read on
The point here is that if we want to take the Servlet one step further and further separate business logic from other work, we need to build a micromanagement, hard work, magic power on top of the Servlet… (Uh…) To do the work for us, let’s call this Servlet super Awesome Servlet. And who are the guys who developed Spring that we can think of, they can’t think of? So they went ahead and developed this awesome Servlet and officially named it DispatcherServlet.
3. Spring MVC — Two-level controller approach
Next we will officially start the Spring MVC journey, from the previous understanding, we know that Spring MVC called the super awesome Servlet DispatcherServlet, this Servlet can be said to simplify our development of the heart, we call the front-end controller. Now we can’t help thinking that the BaseServlet we wrote earlier corresponds to the current super awesome Servlet(DispatcherServlet). So what is the name of the custom Servlet that defines our business logic? The Spring MVC class that defines our business logic is called Handler, except it’s not a Servlet anymore, it’s a generic class, which makes sense, because DispatcherServlet does so much, and it’s so cool, You can treat a normal class just like a Servlet, and this Handler is called a secondary controller.
Some of you might object, but some books say that Spring MVC’s secondary Controller is called a Controller, not a Handler.
Spring MVC’s secondary Controller is actually called Handler, but the Hander is an abstraction, and Spring MVC chooses to implement Handler using Controller, so at this point, do you think we can customize a Handler implementation, What about Lellortnoc? Of course the answer is yes! Just as List is an abstract interface, List implementations have ArrayList,LinkedList.
4. DispatcherServlet — Front-end controller
DispatcherServlet is the core of the whole Spring MVC, and he deserves the honor of super awesome Servlet. DispatcherServlet and its family members do a lot of work, including automatic binding of request parameters, automatic validation of parameters, automatic matching of request URL, logical view name to real page, separation of data fetch and data rendering display… In this process, he is more like a conductor, methodically directing requests to be processed continuously, and finally completing the server’s response data.
To learn more about how DispatcherServlet is directed, read on!
5. HandlerMapper — Request mapping expert
Imagine that when we were writing code using servlets, the mapping of requests was handed over to web.xml. But now that Spring MVC has adopted a two-level controller approach, this thorny issue must be addressed.
First of all, the DispatcherServlet is also a Servlet, so we should also configure the request path it handles in web.xml. So what path should be configured? We say DispatcherServlet is called a super Serlvet. We want it to handle all requests, so we can make DispatcherServlet handle all requests. Configure it as follows:
<? xml version="1.0" encoding="UTF-8"? > <web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>Spring MVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <! -- initializes this when the container is startedservlet -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:Spring-servlet.xml</param-value>
</init-param>
<load-on-startup< / a > 1load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC</servlet-name>
<url-pattern/ * < / >url-pattern>
</servlet-mapping>
</web-app>
Copy the code
Now that all requests are mapped to the DispatcherServlet, it is now the responsibility of the DispatcherServlet to distribute requests to specific sub-controllers. How do you find or store this mapping between requests to specific sub-controllers? DispatcherServlet chooses to request its buddy HandlerMapping.
In HandlerMapping, which Handler(usually Controller) should handle a particular request URL is saved. HandlerMapping According to different mapping policies, the following mapping search methods are available:
- Org. Springframework. Web. Servlet. Handler. SimpleUrlHandlerMapping through configuration request path and Controller mapping relationship, find the corresponding Controller
- Org. Springframework. Web. Servlet. MVC. Support. ControllerClassNameHandlerMapping find the requested Controller through the class name of the Controller.
- Org. Springframework. Web. Servlet. Handler. BeanNameUrlHandlerMapping by defining the beanName to look up to the request of the Controller
- Org. Springframework. Web. Servlet. MVC. The annotation. DefaultAnnotationHandlerMapping through annotations @ RequestMapping (“/userlist “) To find the corresponding Controller.
The most common type is the fourth one, which allows you to configure the requested mapping directly by adding annotations to the corresponding Controller and its internal methods.
HandlerInterceptor HandlerInterceptor
While we’re at it, Do you think the DispatcherServlet sends the requested URL to the HandlerMapping, and the HandlerMapping finds the Controller for the request and gives it to the DispatcherServlet? And then the DispatcherServlet goes to the Controller and it’s done, okay? So, To young To native, there’s a little bit of an interlude. For example, we cannot hand over all requests to the Handler for execution, at least filter unreasonable requests, such as checking the Session when jumping to the page, if the user does not log in to the login interface, and some abnormalities of the program jump in a unified way, etc., all need to intercept requests.
Does that sound a little familiar to those of you who know servlets? True, the Filter in the Servlet can also intercept and Filter requests. However, since Spring MVC is a two-level controller architecture, HandlerInterceptor has a few subtle differences from the Filter. The main difference is that I think HandlerInterceptor provides a finer granularity of interception. After all, a Filter intercepts a Serlvet, while a HandlerInterceptor intercepts a Handler(Controller). It can be graphically represented in a picture.
As you can see from the figure, HandlerInteceptor can be configured in multiple ways. If any of them returns false, the request will be intercepted and returned directly.
7. Secondary controller — Handler
The front controller is already familiar, and the secondary controller, the Handler, is the class where we actually perform the business logic. Usually in Spring MVC, this Handler is known as a Controller. This is where we call the encapsulated business logic interface. It’s safe to say that Spring MVC has separated the business logic from the rest of the unrelated work quite thoroughly. So let’s concentrate on writing our business logic in Handler(Controller).
A bridge between HandlerInterceptor and HandlerExecutionChain
DispatherServlet turns to HandlerMapping to map urls to secondary controllers. However, after handing urls to specific HandlerMapping, Instead of an executable Handler(Controller), a HandlerExecutionChain object is returned to the DispaterServlet after a ferocious HandlerMapping operation. So why on earth would HandlerMapping return such an object instead of a Handler object?
Do you have to wonder how the HandlerInterceptor and Handler are connected? The answer is HandlerExecutionChain. It is a combination of several handlerInterceptors and handlers. So how do you put it together?
In the design pattern, HandlerExecutionChain strings HandlerInterceptor and Handler into a chain of execution. First, the request will be intercepted by the first HandlerInterceptor. If false is returned, the request will be short-circuited. If true, the request will be handled by the second HandlerInterceptor. The request will not reach the Handler(Controller) until all the handlerInterceptors have passed. Sends the request to Handler for formal processing. When the execution is complete, go back layer by layer.
The DispatcherServlet takes this HandlerExecutionChain and executes the requests sequentially.
9. Key to decoupling — ModelAndView
At this point, the request finally arrives at the corresponding Handler. We want the Handler to handle only the business logic that is responsible for it, but not for url jumps and so on. The DispatcherServlet then uses the ModelAndView to hold our data and the path we want to jump to.
We call the business logic layer to get the data, encapsulate the data in ModelAndView, and set the view logical view name for ModelAndView. As you can see from the name of ModelAndView, it holds the data that needs to be sent to the front end after the Handler completes execution, as well as the path to jump to. These are what DispatcherServlet needs.
10. View Render Lookup — ViewResolver
This step is the key to Spring MVC separating the retrieval of data from the rendering of the data. The front end may display the data in a variety of ways, be it Jsp, Html, or other. The DispatcherServlet has received the ModelAndView, which contains the response result data returned after executing the request, as well as the path of the logical view. At this time, DispatcherServlet needs to find who can parse and render the data according to the path of the logical view.
Let’s say we use the FreeMarker template engine to render data, and then we need to find a View implementation class that can do the job. How do we do that? With what strategy? This depends on our ViewResolver.
Common search strategies include the following:
- BeanNameViewResolver: Resolves the logical view name to a Bean whose ID is equal to the logical view name.
- XmlViewResolver: Similar to BeanNameViewResolver, except that the target view Bean object is defined in a separate XML file rather than in the main configuration file of the DispatcherServlet context
- InternalResourceViewResovlver: the view name resolves to a URL files, generally use the parser to map view name is stored in the WEB – INF directory program files (such as JSP)
- XsltViewResolver: Resolves the view name into a URL file that specifies an XSLT stylesheet
- JasperReportsViewResolver: JasperReports is a java-based open source reporting tools, the parser will view name resolves to report file corresponding to the URL
- FreeMarkerViewResolver: Resolves to a template file based on FreeMarker template technology
- VelocityViewResolver and VelocityLayoutViewResolver: resolved as template files based on Velocity templates
11. Data rendering — View
After finding the corresponding View implementation class with the help of ViewResolver according to the logical View name, DispatcherServlet will deliver the data in ModelAndView to the View implementation class for rendering. After the View rendering is completed, The rendered data will be delivered to DispatcherServlet, which will then encapsulate it into Response and return it to the front-end display.
At this point, the entire Spring MVC process is complete, of course, there will be support for internationalization, theme definition and setting, but these are not commonly used, the main Spring MVC process needs to use these classes. As you can see, the DispatcherServlet plays a crucial role in this process, so the heart of Spring MVC lies in the DispatcherServlet.
Finally, a flow chart is attached to summarize the above content.
If you feel good, please give a thumbs-up. Your support and encouragement are the driving force of my creation!