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--
Editor to share with you how to achieve DispatcherServlet initialization and request forwarding in SpringMVC. I hope you will get something after reading this article. Let's discuss it together.
When we first learned Servlet programming and java web, we didn't have that many frameworks. The simple thing we need to do to develop a simple feature is to inherit HttpServlet, rewrite the doGet,doPost method as needed, and jump to our defined jsp page. After the Servlet class is written, register the Servlet class in web.xml.
Apart from that, there is nothing else. We start the web server, enter the address in the browser, and we can see the output of the page we have written on the browser. To better understand the above process, you need to learn about the three phases of the Servlet life cycle, known as "init-service-destroy."
I think the above knowledge is enough for you to understand the design ideas of SpringMVC. SpringMVC can certainly be called a complex framework, but at the same time it follows the simplest rule in the Servlet world, and that is "init-service-destroy". We want to analyze the initialization process of SpringMVC, which is actually analyzing the init () method of the DispatcherServlet class. With this simple point of view, let's take a look at the source code of DispatcherServlet.
Configuration element reading
Open the source code of the DispatcherServlet class with Eclipse IDE and take a look at it by ctrl+T.
The initialization entry method init () of the DispatcherServlet class is defined in the parent class HttpServletBean. As a class that directly inherits from the HttpServlet class, the HttpServletBean class overrides the init () method of the HttpServlet class and implements its own initialization behavior.
@ Override public final void init () throws ServletException {if (logger.isDebugEnabled ()) {logger.debug ("Initializing servlet'" + getServletName () + "'");} / / Set bean properties from init parameters. Try {PropertyValues pvs = new ServletConfigPropertyValues (getServletConfig (), this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess (this); ResourceLoader resourceLoader = new ServletContextResourceLoader (getServletContext ()); bw.registerCustomEditor (Resource.class, new ResourceEditor (resourceLoader, this.environment)); initBeanWrapper (bw) Bw.setPropertyValues (pvs, true);} catch (BeansException ex) {logger.error ("Failed to set bean properties on servlet'" + getServletName () + ", ex); throw ex;} / / Let subclasses do whatever initialization they like. InitServletBean (); if (logger.isDebugEnabled ()) {logger.debug ("Servlet'" + getServletName () + "'configured successfully");}}
The initServletBean () method here is an empty method without any implementation in the HttpServletBean class, and its purpose is to leave the subclass to implement its own initialization logic, which is what we often call the template method design pattern. SpringMVC vividly uses this pattern. The init () method is the template method in the template method pattern. The real initialization process of SpringMVC is triggered by the initServletBean () method overridden in the subclass FrameworkServlet.
Take another look at the code wrapped in try,catch blocks in the init () method, which involves BeanWrapper,PropertyValues,ResourceEditor, which is very low-level classes within Spring. To delve into the details of the specific code implementation, you need to have a fairly in-depth understanding of the Spring framework source code. Let's avoid complexity and simplify here, and analyze what the code in this try,catch block does in terms of code effects and design ideas:
Register a string to the editor of the resource file so that the configuration elements under Servlet can specify the source of the SpringMVC framework bean configuration file in a way such as "classpath:".
Read the configuration elements in web.xml under the DispatcherServlet Servlet into DispatcherServlet using the JavaBean method (that is, through the setter method).
I would like to illustrate these two points through the following example.
The DispatcherServlet configuration I registered with web.xml is as follows:
AppServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring/spring-servlet.xml 1 appServlet /
As you can see, I have registered an element called contextConfigLocation with a value of "classpath:spring/spring-servlet.xml", which is often used to specify the path to the SpringMVC profile. The above try,catch block package code plays the role of converting the string "classpath:spring/spring-servlet.xml" into a resource file under the classpath path for the framework to initialize to read configuration elements. In my project is the configuration file spring-servlet.xml under the spring folder.
Another function is to read out the value of contextConfigLocation and set it to DispatcherServlet through the setContextConfigLocation () method, which is defined in the FrameworkServlet class, which inherits the direct parent class of DispatcherServlet in the class diagram above.
We put a breakpoint on the setContextConfigLocation () method to start the web project, and we can see the following debugging results.
The author of the HttpServletBean class is Rod Johnson, the famous father of Spring. As a master of POJO programming philosophy, he used the idea of dependency injection to complete the reading of configuration elements in the design of HttpServletBean class. That's why he pulled out the HttpServletBean class, which is to "read the configuration information of the Servlet class in the form of dependency injection," and this is obviously a kind of setter injection.
Once we understand the design idea of the HttpServletBean class, we know how we can benefit from it. Specifically, we inherit the HttpServletBean class (as DispatcherServlet does), define a property in the class, and add the setter method to the attribute, so we can define the value in the element. After the class is initialized, the value will be injected, and we can use it directly, avoiding the use of the templated getInitParameter () method, and also enjoy the function of the resource editor in Spring for free. You can specify the resource file under the classpath directly through "classpath:" in web.xml.
Note that although SpringMVC itself uses strings to declare and set contextConfigLocation parameters for the convenience of initializing the context later, it can also be successfully obtained by declaring it as a Resource type. Readers are encouraged to inherit HttpServletBean to write a test Servlet class and set a parameter to debug, which will help you better understand the process of getting configuration parameters.
Establishment of container context
As mentioned in the previous article, SpringMVC uses the Spring container to accommodate its own configuration elements and has its own bean container context. A critical step during SpringMVC initialization is to establish the container context, which takes place in the FrameworkServlet class and is triggered by the initServletBean () method in the init () method above.
@ Override protected final void initServletBean () throws ServletException {getServletContext () .log ("Initializing Spring FrameworkServlet'" + getServletName () + "'"); if (this.logger.isInfoEnabled ()) {this.logger.info ("FrameworkServlet'" + getServletName () + "': initialization started");} long startTime = System.currentTimeMillis () Try {this.webApplicationContext = initWebApplicationContext (); initFrameworkServlet ();} catch (ServletException ex) {this.logger.error ("Context initialization failed", ex); throw ex } catch (RuntimeException ex) {this.logger.error ("Context initialization failed", ex); throw ex;} if (this.logger.isInfoEnabled ()) {long elapsedTime = System.currentTimeMillis ()-startTime This.logger.info ("FrameworkServlet'" + getServletName () + "': initialization completed in" + elapsedTime + "ms");}}
The initFrameworkServlet () method is an empty method without any implementation, except for some boilerplate code, and what the initServletBean () method does is clear:
This.webApplicationContext = initWebApplicationContext ()
This simple and straightforward code reveals the design purpose of the FrameworkServlet class in the SpringMVC class architecture, which is used to extract the process of establishing the WebApplicationContext context.
The initWebApplicationContext () method encapsulates the entire process of establishing the context of the Spring container. The logic in the method is as follows:
Get the root context initialized by ContextLoaderListener and registered in ServletContext, marked as rootContext
If the webApplicationContext is no longer empty, the Servlet class is programmatically registered with the container (ServletContext.addServlet () in Servlet 3.0 +), and the context is passed in by the programmer. If the incoming context has not been initialized, set the rootContext context to its parent context, and then initialize it, otherwise use it directly.
Determine whether the context has been set in step 2 by whether the reference of the wac variable is null (that is, whether the context has been programmatically passed in). If the wac==null is set, it means that the Servlet is not registered by the programmer into the container. At this point, take the value of the contextAttribute attribute as the key, look for the context in ServletContext, and find it, indicating that the context has been initialized and registered under contextAttribute in another way, and can be used directly.
Check whether the reference of the wac variable is null. If wac==null is established, the context initialization strategy in steps 2 and 3 is not successful. Call createWebApplicationContext (rootContext) to create a new context with rootContext as the parent context as the container context of the SpringMVC configuration element. In most cases, the context we use is the context of this new creation.
The above three policies for initializing the context all call back the onRefresh (ApplicationContext context) method (the callback method varies according to different policies). The onRefresh method is overridden in the DispatcherServlet class to initialize the default implementation class in SpringMVC based on the context obtained above.
Finally, publish the context to ServletContext, that is, set the context to a property of ServletContext with a key to a value related to the servlet class's registered name in web.xml. You can decide whether to publish to ServletContext by changing the value of publishContext, which defaults to true.
By tracking the code in the FrameworkServlet class at the above six points, you can clearly understand the establishment process of the entire container context, and then you can understand the design purpose of the FrameworkServlet class, which is used to establish a Spring container context associated with Servlet and register it with ServletContext. By jumping away from the SpringMVC system, we can also get the benefits of integration with the Spring container by inheriting the FrameworkServlet class. FrameworkServlet, like HttpServletBean, is a class that can be used independently. The principle of opening and closing is reflected everywhere in the whole SpringMVC design, and this is obviously one of them.
Initialize the SpringMVC default implementation class
The initialization process flows in the FrameworkServlet class, establishes the context, and enters the DispatcherServlet class through the callback of the onRefresh (ApplicationContext context) method.
@ Override protected void onRefresh (ApplicationContext context) {initStrategies (context);}
The DispatcherServlet class overrides the onRefresh (ApplicationContext context) method in the parent class FrameworkServlet, providing initialization of various programming elements of SpringMVC. Of course, these programming elements exist as bean in the context of the container. The specific initialization strategy is encapsulated in the initStrategies () method.
Protected void initStrategies (ApplicationContext context) {initMultipartResolver (context); initLocaleResolver (context); initThemeResolver (context); initHandlerMappings (context); initHandlerAdapters (context); initHandlerExceptionResolvers (context); initRequestToViewNameTranslator (context); initViewResolvers (context); initFlashMapManager (context);}
We take the initHandlerMappings (context) method as an example to analyze the initialization strategies of these SpringMVC programming elements. Other methods are initialized with similar policies.
Private void initHandlerMappings (ApplicationContext context) {this.handlerMappings = null; if (this.detectAllHandlerMappings) {/ / Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors (context, HandlerMapping.class, true, false); if (! matchingBeans.isEmpty ()) {this.handlerMappings = new ArrayList (matchingBeans.values ()); / / We keep HandlerMappings in sorted order. OrderComparator.sort (this.handlerMappings);}} else {try {HandlerMapping hm = context.getBean (HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList (hm) } catch (NoSuchBeanDefinitionException ex) {/ / Ignore, we'll add a default HandlerMapping later. }} / / Ensure we have at least one HandlerMapping, by registering / / a default HandlerMapping if no other mappings are found. If (this.handlerMappings = = null) {this.handlerMappings = getDefaultStrategies (context, HandlerMapping.class); if (logger.isDebugEnabled ()) {logger.debug ("No HandlerMappings found in servlet'" + getServletName () + "': using default");}
The detectAllHandlerMappings variable defaults to true, so when initializing the default implementation class of the HandlerMapping interface, all Bean of type HandlerMapping in the context is registered in the List variable handlerMappings. If you set it to false manually, you will try to get a Bean named handlerMapping, create a new List with only one element, and assign it to handlerMappings. If the handlerMappings variable is still empty after the above procedure, you have not provided a Bean definition of your own HandlerMapping type in the context. At this point, SpringMVC will initialize handlerMappings with the default initialization policy.
Click in getDefaultStrategies to have a look.
@ SuppressWarnings ("unchecked") protected List getDefaultStrategies (ApplicationContext context, Class strategyInterface) {String key = strategyInterface.getName (); String value = defaultStrategies.getProperty (key); if (value! = null) {String [] classNames = StringUtils.commaDelimitedListToStringArray (value); List strategies = new ArrayList (classNames.length) For (String className: classNames) {try {Class clazz = ClassUtils.forName (className, DispatcherServlet.class.getClassLoader ()); Object strategy = createDefaultStrategy (context, clazz) Strategies.add (T) strategy) } catch (ClassNotFoundException ex) {throw new BeanInitializationException ("Could not find DispatcherServlet's default strategy class [" + className +) "] for interface [" + key + "]" Ex) } catch (LinkageError err) {throw new BeanInitializationException ("Error loading DispatcherServlet's default strategy class [" + className +) "] for interface [" + key + "]: problem with class file or dependent class" Err) } return strategies;} else {return new LinkedList ();}}
It is a generic method that assumes the default initialization policy for all SpringMVC programming elements. The content of the method is relatively straightforward, which is to pass the name of the class as the key, get the implementation class from the Properties variable defaultStrategies, and then reflect the initialization.
What needs to be noted is the initialization of the defaultStrategies variable, which is loaded in the static initialization code block of DispatcherServlet.
Private static final Properties defaultStrategies; static {/ / Load default strategy implementations from properties file. / / This is currently strictly internal and not meant to be customized / / by application developers. Try {ClassPathResource resource = new ClassPathResource (DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties (resource);} catch (IOException ex) {throw new IllegalStateException ("Could not load 'DispatcherServlet.properties':" + ex.getMessage ()) }} private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties"
In this DispatcherServlet.properties, the SpringMVC default implementation class is recorded in the way of key-value pairs, which is in the jar package spring-webmvc-3.1.3.RELEASE.jar and in the org.springframework.web.servlet package.
# Default implementation classes for DispatcherServlet's strategy interfaces.# Used as fallback when no matching beans are found in the DispatcherServlet context.# Not meant to be customized by application developers.org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter \ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver \ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
At this point, we have analyzed the execution of the initHandlerMappings (context) method, and the other initialization processes are very similar to this method. After all the initialization methods are executed, SpringMVC officially completes the initialization and waits for the arrival of the Web request.
After reading this article, I believe you have a certain understanding of "how to achieve DispatcherServlet initialization and request forwarding in SpringMVC". If you want to know more about it, you are welcome to follow the industry information channel. Thank you for reading!
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.