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--
Today, the editor will share with you the relevant knowledge of what the principle of Spring MVC is. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article. Let's take a look at it.
SpringMVC is a lightweight Web framework that implements the request-driven type of Web MVC design pattern based on Spring. It uses the idea of MVC architecture pattern to decouple the Web layer and manage the life cycle of the application, which provides great convenience for simplifying daily development.
1. Brief introduction
In the last article, I showed you how Spring MVC handles HTTP requests. When Spring MVC can provide services, it shows that it is already in a ready state. Before again, Spring MVC needs to perform a series of initialization operations. As the saying goes, before the troops move, food and forage comes first. These operations include creating containers, loading various components used in DispatcherServlet, and so on. In this article, we will discuss the container creation operations in these initialization operations, which are the basis of some other initialization processes. Then I won't say much else. Let's get to the point.
two。 The process of creating a container
In general, we will configure two containers in one Web application. A container is used to load classes in the Web layer, such as our interfaces Controller, HandlerMapping, ViewResolver, and so on. In this article, we call this container the web container. Another container is used to load classes related to business logic, such as classes in the service and dao layers. In this article, we call this container a business container. In the process of container initialization, the business container initializes before the web container. When the web container is initialized, the business container is used as the parent container. The reason for this is that some of the bean in the web container depends on the bean in the business container. For example, our controller layer interfaces usually rely on the business logic classes of the service layer.
Here is an example to illustrate:
We configure the classes of the dao layer in the application-dao.xml file and the classes of the service layer in the application-service.xml file. Then we import these two configuration files into the application.xml file through tags. At this point, we can ask the business container to load the application.xml configuration file. On the other hand, we put the Web-related configuration in the application-web.xml file and give it to the Web container to load.
Here we layer the configuration file, which looks much clearer in structure and easy to maintain. This is actually the same reason as code layering, how uncomfortable it would look if we put all the code in the same package. Similarly, it is a hierarchical representation that we use business containers and Web containers to load different classes. Of course, if the application is relatively simple, it is not impossible to use only the Web container to load all the classes.
2.1 the process of creating a business container
Having mentioned some background knowledge as a groundwork, let's start to analyze the container creation process. In the order of creation, let's first analyze the process of creating a business container. The creation entry of the business container is the contextInitialized method of ContextLoaderListener. As the name implies, ContextLoaderListener is used to listen for ServletContext load events. When the ServletContext is loaded, the listener's contextInitialized method is called by the Servlet container. Provided by the ContextLoaderListener Spring framework, its configuration method is as follows:
Org.springframework.web.context.ContextLoaderListenercontextConfigLocationclasspath:application.xml
As mentioned above, ContextLoaderListener can obtain the contextConfigLocation configuration through ServletContext. This allows the business container to load the application.xml configuration file. Then let's analyze the source code of ContextLoaderListener.
Public class ContextLoaderListener extends ContextLoader implements ServletContextListener {/ / omit part of the code @ Overridepublic void contextInitialized (ServletContextEvent event) {/ / initialize WebApplicationContextinitWebApplicationContext (event.getServletContext ());}} public WebApplicationContextinitWebApplicationContext (ServletContext servletContext) {/ * * if the value * of the ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE property in ServletContext is not empty, it indicates that another listener has set this property. Spring believes that the property value of * set by other listeners cannot be replaced, so an exception is thrown here. * / if (servletContext.getAttribute (WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)! = null) {throw new IllegalStateException ("Cannot initialize context because there is already a root application context present -" + "check whether you have multiple ContextLoader* definitions in your web.xml!");} Log logger = LogFactory.getLog (ContextLoader.class); servletContext.log ("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled ()) {.} long startTime = System.currentTimeMillis () Try {if (this.context = = null) {/ / create WebApplicationContextthis.context = createWebApplicationContext (servletContext);} if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (! cwac.isActive ()) {if (cwac.getParent () = = null) {/ * * load parent ApplicationContext. In general, the business container will not have a parent container, * unless configured * / ApplicationContext parent = loadParentContext (servletContext); cwac.setParent (parent) } / / configure and refresh WebApplicationContextconfigureAndRefreshWebApplicationContext (cwac, servletContext);} / set ApplicationContext to servletContext servletContext.setAttribute (WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader ccl = Thread.currentThread (). GetContextClassLoader (); if (ccl = = ContextLoader.class.getClassLoader ()) {currentContext = this.context;} else if (ccl! = null) {currentContextPerThread.put (ccl, this.context) } if (logger.isDebugEnabled ()) {...} if (logger.isInfoEnabled ()) {...} return this.context;} catch (RuntimeException ex) {logger.error ("Context initialization failed", ex); servletContext.setAttribute (WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex;} catch (Error err) {logger.error ("Context initialization failed", err); servletContext.setAttribute (WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err;}
As above, let's take a look at the creation process above. First of all, Spring will check whether the ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE property in the ServletContext has been set, and if so, throw an exception. If not, the createWebApplicationContext method is called to create the container. Once created, call the configureAndRefreshWebApplicationContext method to configure and refresh the container. Finally, the setAttribute method is called to set the container to ServletContext. After the above steps, the whole creation process is over. The process is not complicated and can be simply summarized as creating a container → configuration and refreshing the container → settings container to ServletContext. In this three-step process, the last step is not analyzed, and then the source code corresponding to the first and second steps is analyzed. As follows:
Protected WebApplicationContext createWebApplicationContext (ServletContext sc) {/ / determines what type of container to create. The default type is XmlWebApplicationContextClass > contextClass = determineContextClass (sc); if (! ConfigurableWebApplicationContext.class.isAssignableFrom (contextClass)) {throw new ApplicationContextException ("Custom context class [" + contextClass.getName () + "] is not of type [" + ConfigurableWebApplicationContext.class.getName () + "]);} / / create container return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass (contextClass) through reflection } protected Class > determineContextClass (ServletContext servletContext) {/ * * read user-defined configuration, for example: * * contextClass * XXXConfigWebApplicationContext * * / String contextClassName = servletContext.getInitParameter (CONTEXT_CLASS_PARAM); if (contextClassName! = null) {try {return ClassUtils.forName (contextClassName, ClassUtils.getDefaultClassLoader ());} catch (ClassNotFoundException ex) {throw new ApplicationContextException ("Failed to load custom context class [" + contextClassName + "]", ex) }} else {/ * * if there is no custom configuration, get the default container type, which is XmlWebApplicationContext. * the configuration file read by defaultStrategies is ContextLoader.properties,*, which contains the following contents: * org.springframework.web.context.WebApplicationContext = * org.springframework.web.context.support.XmlWebApplicationContext*/contextClassName = defaultStrategies.getProperty (WebApplicationContext.class.getName ()); try {return ClassUtils.forName (contextClassName, ContextLoader.class.getClassLoader ());} catch (ClassNotFoundException ex) {throw new ApplicationContextException ("Failed to load default context class [" + contextClassName + "]", ex);}
Briefly talking about the flow of the createWebApplicationContext method, the method first calls determineContextClass to determine what type of container to create, which defaults to XmlWebApplicationContext. Then call the instantiateClass method to create the container instance by reflection. InstantiateClass method does not follow the analysis, you can go to see for yourself, it is relatively simple.
Moving on, let's take a look at the source code of the configureAndRefreshWebApplicationContext method. As follows:
Protected void configureAndRefreshWebApplicationContext (ConfigurableWebApplicationContext wac, ServletContext sc) {if (ObjectUtils.identityToString (wac) .equals (wac.getId () {/ / get the user-configured contextId attribute String idParam = sc.getInitParameter (CONTEXT_ID_PARAM) from ServletContext; if (idParam! = null) {/ / set container idwac.setId (idParam) } else {/ / user does not configure contextId, then set a default container idwac.setId (ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString (sc.getContextPath ();}} wac.setServletContext (sc); / / get contextConfigLocation configuration String configLocationParam = sc.getInitParameter (CONFIG_LOCATION_PARAM); if (configLocationParam! = null) {wac.setConfigLocation (configLocationParam);} ConfigurableEnvironment env = wac.getEnvironment (); if (env instanceof ConfigurableWebEnvironment) {(ConfigurableWebEnvironment) env) .initPropertySources (sc, null) } customizeContext (sc, wac); / / refresh container wac.refresh ();}
The above source code is not very long, the logic is not very complex. Here is a brief summary of the main things done by the configureAndRefreshWebApplicationContext method, as follows:
Set the container id to get the contextConfigLocation configuration, and set it to the container to refresh the container. The process of creating a business container is analyzed. Let's continue to analyze the process of creating a Web container.
2.2 the process of creating Web containers
I talked about the process of creating a business container, which is through ContextLoaderListener. So what is the Web container created from? The answer is through DispatcherServlet. When I introduced the HttpServletBean abstract class in my previous article, I said that it overrides the init method in the parent class HttpServlet. This method is to create the entry of the Web container, so let's start with this method. As follows:
/ /-☆-org.springframework.web.servlet.HttpServletBeanpublic final void init () throws ServletException {if (logger.isDebugEnabled ()) {} / / get the configuration information in ServletConfig PropertyValues pvs = new ServletConfigPropertyValues (getServletConfig (), this.requiredProperties); if (! pvs.isEmpty ()) {try {/ * * create a BeanWrapper,* convenient read / write object property for the current object (such as DispatcherServlet object). * / BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess (this); ResourceLoader resourceLoader = new ServletContextResourceLoader (getServletContext ()); bw.registerCustomEditor (Resource.class, new ResourceEditor (resourceLoader, getEnvironment (); initBeanWrapper (bw); / / set configuration information to bw.setPropertyValues (pvs, true) in the target object;} catch (BeansException ex) {if (logger.isErrorEnabled ()) {...} throw ex;}} / / for subsequent initialization initServletBean () If (logger.isDebugEnabled ()) {...}} protected void initServletBean () throws ServletException {}
The main thing the above source code does is to set the configuration information in ServletConfig to a subclass object of HttpServletBean (such as DispatcherServlet). We do not find any traces of container creation in the above source code. However, if you pay attention to the source code, you will find that initServletBean this method is a little strange, is an empty method. The access level of this method is protected, which can be overridden by subclasses. The HttpServletBean subclass FrameworkServlet overrides this method, so let's explore it in FrameworkServlet.
/ /-☆-org.springframework.web.servlet.FrameworkServletprotected final void initServletBean () throws ServletException {getServletContext (). Log ("Initializing Spring FrameworkServlet'" + getServletName () + "'"); if (this.logger.isInfoEnabled ()) {.} long startTime = System.currentTimeMillis (); try {/ / initialize container 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 ()) {...}} protected WebApplicationContext initWebApplicationContext () {/ / get the container from ServletContext, that is, the container created by ContextLoaderListener WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext (getServletContext ()); WebApplicationContext wac = null;/** if the following conditions are true, webApplicationContext needs to be set externally. There are two ways to set * webApplicationContext. Take DispatcherServlet as an example: * 1. Pass the WebApplicationContext object * 2 through the DispatcherServlet parameter construction method. Configure DispatcherServlet to other containers, which can be set by * setApplicationContext method * *. For more information, please see the source code of * registerDispatcherServlet method in AbstractDispatcherServletInitializer. In general, the code is executed here, and * this.webApplicationContext is null. You can debug and verify it by yourself. * / if (this.webApplicationContext! = null) {wac = this.webApplicationContext;if (wac instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;if (! cwac.isActive ()) {if (cwac.getParent () = = null) {/ / set rootContext as the parent container cwac.setParent (rootContext);} / configure and refresh container configureAndRefreshWebApplicationContext (cwac);}} if (wac = = null) {/ / attempt to get container wac = findWebApplicationContext () from ServletContext } if (wac = = null) {/ / create the container with rootContext as the parent container wac = createWebApplicationContext (rootContext);} if (! this.refreshEventReceived) {onRefresh (wac);} if (this.publishContext) {String attrName = getServletContextAttributeName (); / / set the created container to ServletContext getServletContext (). SetAttribute (attrName, wac); if (this.logger.isDebugEnabled ()) {...}} return wac } protected WebApplicationContext createWebApplicationContext (ApplicationContext parent) {/ / get container type, default is XmlWebApplicationContext.classClass > contextClass = getContextClass (); if (this.logger.isDebugEnabled ()) {} if (! ConfigurableWebApplicationContext.class.isAssignableFrom (contextClass)) {throw new ApplicationContextException ("Fatal initialization error in servlet with name'" + getServletName () + "': custom WebApplicationContext class [" + contextClass.getName () + "] is not of type ConfigurableWebApplicationContext");} / / instantiate container ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass (contextClass) by reflection Wac.setEnvironment (getEnvironment ()); wac.setParent (parent); wac.setConfigLocation (getContextConfigLocation ()); / / configure and refresh container configureAndRefreshWebApplicationContext (wac); return wac;} protected void configureAndRefreshWebApplicationContext (ConfigurableWebApplicationContext wac) {if (ObjectUtils.identityToString (wac) .equals (wac.getId () {/ / set container idif (this.contextId! = null) {wac.setId (this.contextId) } else {/ / generate default idwac.setId (ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString (getServletContext (). GetContextPath ()) +'/'+ getServletName ();}} wac.setServletContext (getServletContext ()); wac.setServletConfig (getServletConfig ()); wac.setNamespace (getNamespace ()); wac.addApplicationListener (new SourceFilteringListener (wac, new ContextRefreshListener (); ConfigurableEnvironment env = wac.getEnvironment (); if (env instanceof ConfigurableWebEnvironment) {(ConfigurableWebEnvironment) env) .initPropertySources (getServletContext (), getServletConfig ()) } / / Post processing, subclasses can override and do some custom operations. Not used in Spring MVC, it is an empty method. PostProcessWebApplicationContext (wac); applyInitializers (wac); / / refresh container wac.refresh ();}
The above is the source code for creating a Web container. Let's summarize the process of creating the container. As follows:
Get the container created by ContextLoaderListener from ServletContext if the this.webApplicationContext! = null condition is established, you can try to get the container from ServletContext by simply setting the parent container and refreshing the container. If the container is not empty, you do not need to perform step 4 to create the container, and use rootContext as the parent container to set the container to ServletContext. Here, the process of creating a Web container is over. In general, the process of creating a Web container is roughly the same as that of a business container, but there are differences that cannot be ignored.
These are all the contents of the article "what is the principle of Spring MVC?" Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to 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.