spring mvc 总体启动流程
一、基礎XML配置
? ? ? 1.WEB.xml配置如下
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><display-name>Archetype Created Web Application</display-name><!--welcome pages--><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><!-- <listener><listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class></listener><filter><filter-name>log4jServletFilter</filter-name><filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class></filter><filter-mapping><filter-name>log4jServletFilter</filter-name><url-pattern>/*</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher><dispatcher>INCLUDE</dispatcher><dispatcher>ERROR</dispatcher></filter-mapping>--><!--配置springmvc DispatcherServlet--><servlet><servlet-name>springMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><!--配置dispatcher.xml作為mvc的配置文件--><param-name>contextConfigLocation</param-name><param-value>/dispatcher-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!--<servlet>--><!--<servlet-name>EmpServlet</servlet-name>--><!--<servlet-class>com.gx.filter.EmpServlet</servlet-class>--><!--</servlet>--><servlet-mapping><servlet-name>springMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!--把applicationContext.xml加入到配置文件中--><context-param><param-name>contextConfigLocation</param-name><param-value>/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--<listener>--><!--<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>--><!--</listener>--><!-- <context-param>--> <!-- <param-name>log4jConfigLocation</param-name>--> <!-- <param-value>classpath:log4j2.xml</param-value>--> <!-- </context-param>--></web-app>? ?2.applicationContext.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.tpw.service"/></beans>3.dispatcher-servlet.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--此文件負責整個mvc中的配置--><!--啟用spring的一些annotation --><context:annotation-config/><!-- 配置注解驅動 可以將request參數與綁定到controller參數上 --><mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"/><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></mvc:message-converters></mvc:annotation-driven><bean id="fastjson" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json;charset=UTF-8</value></list></property></bean><!--靜態資源映射--><!--本項目把靜態資源放在了webapp的statics目錄下,資源映射如下--><mvc:resources mapping="/css/**" location="/static/css/"/><mvc:resources mapping="/js/**" location="/static/js/"/><mvc:resources mapping="/image/**" location="/static/images/"/><mvc:default-servlet-handler/> <!--這句要加上,要不然可能會訪問不到靜態資源,具體作用自行百度--><!-- 對模型視圖名稱的解析,即在模型視圖名稱添加前后綴(如果最后一個還是表示文件夾,則最后的斜杠不要漏了) 使用JSP--><!-- 默認的視圖解析器 在上邊的解析錯誤時使用 (默認使用html)- --><bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/><property name="prefix" value="/WEB-INF/"/><!--設置JSP文件的目錄位置--><property name="suffix" value=".jsp"/><property name="exposeContextBeansAsAttributes" value="true"/></bean><!-- 自動掃描裝配 --><context:component-scan base-package="com.tpw.controller"/></beans>二、tomcat容器引擎加載時首先加載web.xml所有配置的listener對象。\
1.我們配置的是
org.springframework.web.context.ContextLoaderListener,所有會加載此類contextInitialized方法,此方法會創建一個父類的applicationContext,加載applicationContext.xml文件中所有的掃描和配置的BEAN,并創建到容器工廠中。 @Overridepublic void contextInitialized(ServletContextEvent event) {initWebApplicationContext(event.getServletContext());}?2.然后會調用org.springframework.web.context.ContextLoader.initWebApplicationContext,創建父類applicationContext,默認為org.springframework.web.context.support.XmlWebApplicationContext類環境。
?
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {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!");}servletContext.log("Initializing Spring root WebApplicationContext");Log logger = LogFactory.getLog(ContextLoader.class);if (logger.isInfoEnabled()) {logger.info("Root WebApplicationContext: initialization started");}long startTime = System.currentTimeMillis();try {// Store context in local instance variable, to guarantee that// it is available on ServletContext shutdown.if (this.context == null) {this.context = createWebApplicationContext(servletContext);}if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (!cwac.isActive()) {// The context has not yet been refreshed -> provide services such as// setting the parent context, setting the application context id, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent ->// determine parent for root web application context, if any.ApplicationContext parent = loadParentContext(servletContext);cwac.setParent(parent);}configureAndRefreshWebApplicationContext(cwac, 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.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime;logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");}return this.context;}catch (RuntimeException | Error ex) {logger.error("Context initialization failed", ex);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);throw ex;}}3.創建完applicationContext后,則會contextLoader.configureAndRefreshWebApplicationContext去配置configlocation的XML,以及ID名稱,然后調用applicationContext.refresh去實例化工廠中的對象。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {if (ObjectUtils.identityToString(wac).equals(wac.getId())) {// The application context id is still set to its original default value// -> assign a more useful id based on available informationString idParam = sc.getInitParameter(CONTEXT_ID_PARAM);if (idParam != null) {wac.setId(idParam);}else {// Generate default id...wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +ObjectUtils.getDisplayString(sc.getContextPath()));}}wac.setServletContext(sc);String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);if (configLocationParam != null) {wac.setConfigLocation(configLocationParam);}// The wac environment's #initPropertySources will be called in any case when the context// is refreshed; do it eagerly here to ensure servlet property sources are in place for// use in any post-processing or initialization that occurs below prior to #refreshConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(sc, null);}customizeContext(sc, wac);wac.refresh();}?4.application.refresh,則會根據applicationContext.xml中定義去掃描或者加載實例化BEAN,這個和spring ioc 原理一樣.
三、org.springframework.web.servlet.DispatcherServlet初始化
? 1.DispatcherServlet靜態代碼執行,會將DispatcherServlet.properties配置的相應工廠SPI類配置讀取出來到屬性列表中。
包中的配置文件路徑如下:
文件內容為:
# 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.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\org.springframework.web.servlet.function.support.HandlerFunctionAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\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?2.會調用org.springframework.web.servlet.HttpServletBean.init 進行初始化。創建一個
BeanWrapper屬性包裝器,里面包裝的是DispatcherServlet對象。會將web.xml中 param-name中的值設置到DispatcherServlet對象的屬性包裝器中,如contextConfigLocation屬性設置為dispatcher-servlet.xml。?
public final void init() throws ServletException {// Set bean properties from init parameters.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);}throw ex;}}?
3.調用FrameworkServlet.initServletBean去創建子applicationContext.
protected final void initServletBean() throws ServletException {getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");if (logger.isInfoEnabled()) {logger.info("Initializing Servlet '" + getServletName() + "'");}long startTime = System.currentTimeMillis();try {this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();}catch (ServletException | RuntimeException ex) {logger.error("Context initialization failed", ex);throw ex;}if (logger.isInfoEnabled()) {logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");}}?調用棧
4.初始化applicationContext時首先會獲取父的applicationContext,然后會創建的子CONTEXT,
wac = createWebApplicationContext(rootContext); org.springframework.web.servlet.FrameworkServlet protected WebApplicationContext initWebApplicationContext() {WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;if (this.webApplicationContext != null) {// A context instance was injected at construction time -> use itwac = this.webApplicationContext;if (wac == null) {// No context instance was injected at construction time -> see if one// has been registered in the servlet context. If one exists, it is assumed// that the parent context (if any) has already been set and that the// user has performed any initialization such as setting the context idwac = findWebApplicationContext();}if (wac == null) {// No context instance is defined for this servlet -> create a local onewac = createWebApplicationContext(rootContext);}if (!this.refreshEventReceived) {// Either the context is not a ConfigurableApplicationContext with refresh// support or the context injected at construction time had already been// refreshed -> trigger initial onRefresh manually here.synchronized (this.onRefreshMonitor) {onRefresh(wac);}}if (this.publishContext) {// Publish the context as a servlet context attribute.String attrName = getServletContextAttributeName();getServletContext().setAttribute(attrName, wac);}return wac;}?5.創建新的子applicationContext,并調用其refresh方法。設置根applicationContext為父。后面的refresh就是掃描dispatch-servlet.xml中的所有配置包,然后加載和實例化到容器工廠中。
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {Class<?> contextClass = getContextClass();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");}ConfigurableWebApplicationContext wac =(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);wac.setEnvironment(getEnvironment());wac.setParent(parent);String configLocation = getContextConfigLocation();if (configLocation != null) {wac.setConfigLocation(configLocation);}configureAndRefreshWebApplicationContext(wac);return wac;}?
?
四、DispatchServlet的onfresh加載流程
1.在上述子applicationContext.refresh調用完畢時,會調用publishEvent(new ContextRefreshedEvent(this)),而DispatcherServlet的父類FrameworkServlet有一個內部類實現了applicationListener接口
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {FrameworkServlet.this.onApplicationEvent(event);}}2.最終會觸發到DispatchServlet.onRefresh接口
?3.最終會初始化springmvc中的各種策略類。這種會創建對象,注入屬性。
protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}最主要的是初始handlerMapping,即根據URL找到對應的handlerAdapter.
?4.初始化handlerAdapter
排序后
?
?5.初始化異常解析器
排序 后
?
?
總結
以上是生活随笔為你收集整理的spring mvc 总体启动流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring5 配置log系统MAVEN
- 下一篇: springmvc path请求映射到b