Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is FrameworkServlet in SpringMVC source code analysis

2025-03-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article introduces the relevant knowledge of "what is FrameworkServlet in SpringMVC source code analysis". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

1.FrameworkServlet

FrameworkServlet inherits from HttpServletBean, while HttpServletBean inherits from HttpServlet,HttpServlet is something inside JavaEE. Let's not discuss it here. It has been something of a framework since HttpServletBean, but HttpServletBean is special. What makes it special is that it does not handle any requests, but only participates in some initialization operations. These are relatively simple, and we have analyzed them in the last article, so we do not analyze HttpServletBean here. Start directly from its subclass FrameworkServlet.

Like all Servlet, FrameworkServlet's processing of requests starts with the service method, so let's take a look at the method FrameworkServlet#service:

@ Override protected void service (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {HttpMethod httpMethod = HttpMethod.resolve (request.getMethod ()); if (httpMethod = = HttpMethod.PATCH | | httpMethod = = null) {processRequest (request, response);} else {super.service (request, response);}}

As you can see, in this method, the current request method is first obtained, and then the patch request is taken extra care, and all other types of requests are processed by super.service.

However, there is no substantive processing of doGet, doPost and other requests in HttpServlet, so the corresponding methods of various requests, such as doDelete, doGet, doOptions, doPost, doPut, doTrace, etc., are rewritten in FrameworkServlet, which means that all methods except doHead are rewritten.

Let's first look at four methods: doDelete, doGet, doPost, and doPut:

Override protected final void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {processRequest (request, response);} @ Override protected final void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {processRequest (request, response);} @ Override protected final void doPut (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {processRequest (request, response);} @ Override protected final void doDelete (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {processRequest (request, response);}

As you can see, the request is handed over to processRequest again, and in the processRequest method, the request is further called to doService to classify different types of requests.

DoOptions and doTrace are slightly different, as follows:

@ Override protected void doOptions (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {if (this.dispatchOptionsRequest | | CorsUtils.isPreFlightRequest (request)) {processRequest (request, response); if (response.containsHeader ("Allow")) {return;}} super.doOptions (request, new HttpServletResponseWrapper (response) {@ Override public void setHeader (String name, String value) {if ("Allow" .equals (name)) {value = (StringUtils.hasLength (value)? Value + ",": ") + HttpMethod.PATCH.name ();} super.setHeader (name, value);}});} @ Override protected void doTrace (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {if (this.dispatchTraceRequest) {processRequest (request, response); if (" message/http ".equals (response.getContentType () {return;} super.doTrace (request, response);}

You can see that there is an extra layer of logic in the processing of these two methods, that is, to choose whether to process the corresponding request in the current method or leave it to the parent class. Because the dispatchOptionsRequest and dispatchTraceRequest variables are false by default, both types of requests are handed over to the parent class by default.

2.processRequest

Let's take a look at processRequest, which is the core method of FrameworkServlet:

Protected final void processRequest (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {long startTime = System.currentTimeMillis (); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext (); LocaleContext localeContext = buildLocaleContext (request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes (); ServletRequestAttributes requestAttributes = buildRequestAttributes (request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager (request); asyncManager.registerCallableInterceptor (FrameworkServlet.class.getName (), new RequestBindingInterceptor ()); initContextHolders (request, localeContext, requestAttributes); try {doService (request, response) } catch (ServletException | IOException ex) {failureCause = ex; throw ex;} catch (Throwable ex) {failureCause = ex; throw new NestedServletException ("Request processing failed", ex);} finally {resetContextHolders (request, previousLocaleContext, previousAttributes); if (requestAttributes! = null) {requestAttributes.requestCompleted ();} logResult (request, response, failureCause, asyncManager); publishRequestHandledEvent (request, response, startTime, failureCause);}}

Although this method is relatively long, its core is the innermost doService method. With doService as the boundary, we can divide the content of this method into three parts:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Before doService, there are mainly some preparatory work, which mainly does two things. The first thing is to get their original saved LocaleContext and RequestAttributes objects from LocaleContextHolder and RequestContextHolder respectively, then call the buildLocaleContext and buildRequestAttributes methods to get the LocaleContext and RequestAttributes objects of the current request, and then set the LocaleContext and RequestAttributes objects of the current request to LocaleContextHolder and RequestContextHolder objects through the initContextHolders method. The second thing is to get the asynchronous manager and set the interceptor.

Then there is the doService method, which is an abstract method. The concrete implementation is in DispatcherServlet, and this Songge is put into DispatcherServlet and analyzed with you.

The third part is finally, which does two things: the first thing is to restore the corresponding objects in LocaleContextHolder and RequestContextHolder to their original state (see step 1), and the second thing is to publish a message of type ServletRequestHandledEvent through the publishRequestHandledEvent method.

After the above analysis, we found that processRequest actually does two main things, the first thing is to deal with LocaleContext and RequestAttributes, and the second thing is to release events. Let's study these two things separately.

2.1 LocaleContext and RequestAttributes

LocaleContext and RequestAttributes are both interfaces, except that the objects stored in them are different.

2.1.1 LocaleContext

LocaleContext holds Locale, that is, localization information, and if we need to support internationalization, we will use Locale.

When internationalizing, if we need to use the Locale object, the first reaction is to get it from HttpServletRequest, like this:

Locale locale = req.getLocale ()

But as we all know, HttpServletRequest only exists in Controller. If we want to get HttpServletRequest in the Service layer, we have to pass parameters from Controller, which is troublesome, especially when the relevant methods in Service have been defined and then modified.

So we are also provided with LocaleContextHolder in SpringMVC, which is used to save the LocaleContext of the current request. When you see LocaleContextHolder do not know if it looks familiar, Song GE in the previous Spring Security series tutorials and you talked about SecurityContextHolder, the two principles are basically the same, are based on ThreadLocal to save variables, and then to ensure that different threads do not interfere with each other, ThreadLocal is not familiar with partners, you can take a look at Song GE's Spring Security series, there has been a detailed analysis before (official account background reply ss).

With LocaleContextHolder, we can get Locale anywhere. For example, in Service, we can get Locale as follows:

Locale locale = LocaleContextHolder.getLocale ()

The above Locale object is actually taken from the LocaleContext in LocaleContextHolder.

It is important to note that there is also a LocaleResolver parser in SpringMVC, so the previous req.getLocale () does not always get the value of Locale. This Song Brother will talk to his friends in detail in a future article.

2.1.2 RequestAttributes

RequestAttributes is an interface that can be used to get/set/remove an attribute.

RequestAttributes has many implementation classes, and the default is ServletRequestAttributes. Through ServletRequestAttributes, we can getRequest, getResponse, and getSession.

In the specific implementation of ServletRequestAttributes, you will use scope parameters to determine whether to operate request or session (if friends do not remember the scope problem in Spring, you can reply to spring on the public account backend and take a look at the free Spring tutorial recorded by Song GE, which is described in it). Let's take a look at the ServletRequestAttributes#setAttribute method (the execution logic of the get/remove method is similar):

Public void setAttribute (String name, Object value, int scope) {if (scope = = 0) {if (! this.isRequestActive ()) {throw new IllegalStateException ("Cannot set request attribute-request is not active anymore!");} this.request.setAttribute (name, value);} else {HttpSession session = this.obtainSession (); this.sessionAttributesToUpdate.remove (name); session.setAttribute (name, value) }}

As you can see, we will first determine that if scope,scope is 0, if request,scope is 1, we will operate session. If you are operating on request, you first need to determine whether the current request has been executed by the isRequestActive method, and if so, no other operations can be done on it (isRequestActive returns false when the requestAttributes.requestCompleted method in the finally code block is executed).

Similar to LocaleContext, RequestAttributes is stored in RequestContextHolder, and the principle of RequestContextHolder is similar to SecurityContextHolder, so I won't repeat it here.

After reading the above explanation, you should find that in SpringMVC, if we need to use request, response and session in places other than Controller, we do not have to pass request, response, session and other objects from Controller every time, we can get them directly through RequestContextHolder, like the following:

ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes (); HttpServletRequest request = servletRequestAttributes.getRequest (); HttpServletResponse response = servletRequestAttributes.getResponse ()

Is it very easy!

2.2 event release

Finally, the event in the processRequest method is published.

The publishRequestHandledEvent method is called in the finally code block to send an event of type ServletRequestHandledEvent, as shown in the following code:

Private void publishRequestHandledEvent (HttpServletRequest request, HttpServletResponse response, long startTime, @ Nullable Throwable failureCause) {if (this.publishEvents & & this.webApplicationContext! = null) {/ / Whether or not we succeeded, publish an event. Long processingTime = System.currentTimeMillis ()-startTime; this.webApplicationContext.publishEvent (new ServletRequestHandledEvent (this, request.getRequestURI (), request.getRemoteAddr (), request.getMethod (), getServletConfig (). GetServletName (), WebUtils.getSessionId (request), getUsernameForRequest (request), processingTime, failureCause, response.getStatus ());}}

As you can see, the event needs to be sent with a publishEvents of true, and this variable defaults to true. If you need to modify the value of this variable, you can configure the value of this variable through the init-param node when you configure DispatcherServlet in web.xml. Normally, this event is always sent, and we can listen to it if the project needs it, as follows:

@ Component public class ServletRequestHandleListener implements ApplicationListener {@ Override public void onApplicationEvent (ServletRequestHandledEvent servletRequestHandledEvent) {System.out.println ("request completed -" + servletRequestHandledEvent.getRequestUrl ());}}

When a request is completed, the event is triggered.

This is the end of the content of "SpringMVC source code analysis of what is FrameworkServlet". Thank you for your reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

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.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report