Spring MVC源码——Servlet WebApplicationContext [TOC]
上一篇笔记中记录了下 Root WebApplicationContext 的初始化代码.这一篇来看 Servlet WebApplicationContext 的初始化代码
DispatcherServlet
是另一个需要在 web.xml
中配置的类, Servlet WebApplicationContext 就由它来创建和初始化.
HttpServletBean HttpServletBean
简单继承了 HttpServlet
, 负责将 init-param 中的参数注入到当前 Servlet
实例的属性中, 并且为子类提供了增加 requiredProperties 的能力. HttpServletBean
并不依赖于 Spring 容器.
来看一下它的 init()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public final void init () 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); } throw ex; } } initServletBean(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private static class ServletConfigPropertyValues extends MutablePropertyValues { public ServletConfigPropertyValues (ServletConfig config, Set<String> requiredProperties) throws ServletException { Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ? new HashSet <>(requiredProperties) : null ); Enumeration<String> paramNames = config.getInitParameterNames(); while (paramNames.hasMoreElements()) { String property = paramNames.nextElement(); Object value = config.getInitParameter(property); addPropertyValue(new PropertyValue (property, value)); if (missingProps != null ) { missingProps.remove(property); } } if (!CollectionUtils.isEmpty(missingProps)) { throw new ServletException ( "Initialization from ServletConfig for servlet '" + config.getServletName() + "' failed; the following required properties were missing: " + StringUtils.collectionToDelimitedString(missingProps, ", " )); } } }
FrameworkServlet FrameworkServlet
是一个更具体的 Servlet 基类. 它有以下两个功能:
每个 servket 管理一个 WebApplicationContext
实例.
无论请求是否成功, 根据请求处理发布事件.
FrameworkServlet
重写了 HttpServletBean
的 initServletBean()
方法, 这个方法会在 所有 servlet 的属性被注入之后执行, 来看一下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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; } ... }
initWebApplicationContext()
方法会初始化并返回一个容器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 protected WebApplicationContext initWebApplicationContext () { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null ; if (this .webApplicationContext != null ) { wac = this .webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { if (cwac.getParent() == null ) { cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null ) { wac = findWebApplicationContext(); } if (wac == null ) { wac = createWebApplicationContext(rootContext); } if (!this .refreshEventReceived) { synchronized (this .onRefreshMonitor) { onRefresh(wac); } } if (this .publishContext) { String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); } return wac; }
onRefresh()
方法供子类来重写, DispatcherServlet
重写了这个方法来初始化 MVC 中的一些组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override protected void onRefresh (ApplicationContext context) { initStrategies(context); } protected void initStrategies (ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
initWebApplicationContext()
方法调用的其他方法其实和 ContextLoader
中的方法比较类似, 这里就不再放上来了, 有兴趣的可以访问我的源码注释