This is the 11th day of my participation in the First Challenge 2022
introduce
The DispatcherServlet is a Servlet, called a front-end controller in SpringMVC, that distributes requests based on their path, type, and so on.
Analysis of the
DispatcherServlet class diagram
The red part in the figure above is the Servlet interface, which is implemented and extended in Springmvc. When I first learned javaweb development, I didn’t start by using various MVC frameworks. Instead, I started by writing simple servlets that inherited HttpServlet and overwrote its service methods. Springmvc also inherits the HttpServlet and rewrites its Service method, and configures the servlet to intercept all requests, thus enabling the DispatcherServlet to distribute all requests.
1. Initialization
Because the DispatcherServlet is actually a Servlet, it also follows the life cycle of the Servlet when configured to work. There are three phases in the Servlet lifecycle:
init()
: Initializes the requestservice()
: Service processing and redirecting after the request is obtaineddistory()
: Destruction after request processing is complete
So when the Tomcat container (servlet container) starts, the initialization method of the servlet is triggered. HttpServletBean implements this method.
@Override
public final void init(a) throws ServletException {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if(! pvs.isEmpty()) {try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throwex; }}// The actual processing is here, implemented by the concrete subclass FrameworkServlet
initServletBean();
}
Copy the code
FrameworkServlet initServletBean method, the real core is initWebApplicationContext ()
protected final void initServletBean(a) throws ServletException {
long startTime = System.currentTimeMillis();
try {
// Initialize the Web container context
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
// ...
}
Copy the code
InitWebApplicationContext core processing method
protected WebApplicationContext initWebApplicationContext(a) {
/ /... Omit some code
// The main logic of this method is to call the onRefresh(ApplicationContext Context) method, which is overridden in the DispatcherServlet class,
// Complete the initialization of the default implementation class in SpringMVC based on the context obtained above.
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
// The onRefresh method is overridden in the DispatcherServlet class, so we can see from this that the Spring container is first created and the DispatcherServlet is initialized via onRefresh method after the Spring bean is successfully created.onRefresh(wac); }}// Publish this context to the ServletContext, that is, set the context as an attribute of the ServletContext, with a key value associated with the Servlet class's registered name in web.xml. You can change it
// publishContext to determine whether to publish to ServletContext. Default is true.
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
Copy the code
The onRefresh(WAC) method calls the specific initialization method of the subclass DispatcherServlet.
/** * This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
** Initialize the strategy objects that this servlet uses. * May be overridden in subclasses in order to initialize further strategy objects. */
protected void initStrategies(ApplicationContext context) {
// Upload the component handler
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
// Processor mapper
initHandlerMappings(context);
// Processor adapter
initHandlerAdapters(context);
// Handler exception collator
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
// View handler
initViewResolvers(context);
initFlashMapManager(context);
}
Copy the code
2. Distribution logic
- When a client initiates a request, the request enters
DispatcherServlet
It does the processingHandler
The lookup. - First according to the request information
HttpServletRequest
, traverses all registeredhandlerMappings
. The returned structure isHandlerExecutionChain
Contains a specific processorhandler
And the interceptorinterceptor
The structure of the. - Access to the
HandlerExcecutionChain
Then, based on the specific processor, through allhandlerAdapters
, return supportedHandlerAdapter
. - In the access to
HandlerAdapter
After that, perform specifichandler
Before, the execution is iteratedHandlerExecutionChain
Preinterceptor method for interceptors inpreHandle()
.If an interceptor’s pre-method executes the post-methodfalse
Is executed directly from the current nodeafterCompletion()
To terminate the request after execution. - According to the
HandlerAdapter
Processor adapters execute specific processorsHandler
Logic. - Specific at execution completion
handler
After that, the execution is iteratedHandlerExecutionChain
Of the interceptorpostHandle
Methods. Handler
It will return after executionModeAndView
.- In the normal case of execution, execution is iterated after rendering the template and before the request is returned
HandlerExecutionChain
Of the interceptorafterCompletion
Methods.
3. Set up the SpringMVC container
According to the class diagram DispatcherServlet is also realized the ApplicationContextAware interface, and xxxAware interface, is a postProcessBeforeInitialization upon initial springbean extension points, Performed by the class ApplicationContextAwareProcessor to specific logic, is simply pass by setApplicationContext ApplicationContext to initializing the bean.
This is how you pass the Spring container (applicationContext) to the DispatcherServlet in SpringBoot. Until to actually perform the DispatcherServlet initialization method when enclosing applicationContext is not empty, so in initWebApplicationContext () method, go first if logic, This is why SpringBoot won’t eventually produce parent-child containers.