Spring MVC初始化过程源码分析 素颜马尾好姑娘i 2021-12-21 04:59 248阅读 0赞 ### 文章目录 ### * 1. 引言 * 2. HttpServletBean * 3. FrameworkServlet * 4. DispatcherServlet * 5. 小结 # 1. 引言 # Spring MVC核心结构图如下所示 ![DispatcherServlet结构图][DispatcherServlet] 其中aware意为感知,实现XXXAware接口就会通过接口的唯一方法setXXX得到ApplicationContext或Environment等。EnvironmentCapable有惟一方法getEnvironment()。同时需要注意的是ApplicationContext为应用上下文,Environment封装了servletContext、servletConfig、JndiProperty、系统环境变量和系统属性等。 # 2. HttpServletBean # HttpServlet的简单扩展,它将配置参数(web.xml中servlet标记中的init-param条目)视为bean属性。 对于任何类型的servlet都是一个方便的超类。他实现了EnvironmentAware和EnvironmentCapable可以获取environment属性。这里主要关注其init()方法。 /** * Map config parameters onto bean properties of this servlet, and * invoke subclass initialization. * @throws ServletException if bean properties are invalid (or required * properties are missing), or if subclass initialization fails. */ @Override 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; } } // 由子类实现初始化 initServletBean(); } 可以看到子类通过重写initServletBean()方法来进一步初始化。 # 3. FrameworkServlet # /** * Overridden method of {@link HttpServletBean}, invoked after any bean properties * have been set. Creates this servlet's WebApplicationContext. */ @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 { //初始化WebApplicationContext this.webApplicationContext = initWebApplicationContext(); //空方法,子类可以重写 initFrameworkServlet(); } catch (ServletException ex) { ... 在FrameworkServlet中重写了initServletBean()方法,其主要做了两件事 //初始化webApplicationContext this.webApplicationContext = initWebApplicationContext(); //初始化FrameworkServlet,模板方法 initFrameworkServlet(); 让我们来了解一下initWebApplicationContext方法 /** * Initialize and publish the WebApplicationContext for this servlet. * <p>Delegates to {@link #createWebApplicationContext} for actual creation * of the context. Can be overridden in subclasses. */ protected WebApplicationContext initWebApplicationContext() { //获取rootContext WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; //如果已经通过构造方法设置了WebApplicationContext if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> set // the root application context (if any; may be null) as the parent cwac.setParent(rootContext); } //configureAndRefreshWebApplicationContext方法用于封装ApplicationContext数据并且初始化所有相关Bean对象。 //它会从web.xml中读取名为contextConfigLocation的配置,这就是spring xml数据源设置,然后放到ApplicationContext中, //最后调用传说中的refresh方法执行所有Java对象的创建 configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { //从servlet context中获取webApplicationContext // 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 id wac = findWebApplicationContext(); } if (wac == null) { //如果从servlet context中找不到就创建一个新的 // No context instance is defined for this servlet -> create a local one wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { //如果没有refresh,在这里刷新 // 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. onRefresh(wac); } if (this.publishContext) { //将ApplicationContext保存到ServletContext中 // Publish the context as a servlet context attribute. String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; } initWebApplicationContext方法做了三件事: 1. 获取spring的根容器rootContext 2. 设置webApplicationContext并根据情况调用onRefresh方法 3. 将webApplicationContext设置到ServletContext中 整个FrameworkServlet中重要的事情就是将创建出来的WebApplicationContext设置到ServletContext中,方便获取。 # 4. DispatcherServlet # onRefresh方法是DispatcherServlet的入口方法,onrefresh调用了initStrategies,在initStrategies中调用了9个初始化方法 protected void onRefresh(ApplicationContext context) { initStrategies(context); } /** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize further strategy objects. */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } # 5. 小结 # 简单分析了一个Spring MVC的创建过程,Spring MVC中Servlet一共有三个层次,分别是HttpServletBean,FrameworkServlet和DispatcherServlet。HttpServletBean直接继承自Java的HttpServlet,其作用是将Servlet中配置的参数设置到对应的属性;FrameworkServlet初始化了WebApplciationContext,DispatcherServlet初始化了自身的9个组件。 [DispatcherServlet]: /images/20211221/794b7832b24a493c99248132c5b05e36.png
还没有评论,来说两句吧...