SpringMvc 启动原理源码分析
了解一个项目启动如何实现是了解一个框架底层实现的一个必不可少的环节。从使用步骤来看,我们一般是引入包之后,配置web.xml文件。官方文档示例的配置如下:
<web-app> <servlet> <servlet-name>example</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>example</servlet-name> <url-pattern>/example/*</url-pattern> </servlet-mapping> </web-app>
其实就是把请求引到DispatcherServlet类中去执行。而DispatcherServlet类其实是一个Servlet类的子类,他的继承结构如下:
我们都知道当项目启动时,servlet会执行init方法,在HttpServletBean中覆写了这个init方法。代码如下
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } // Set bean properties from init parameters. try {
//获取servletConfig PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
//将dispatcherServlet对象封装到BeanWrapper类里 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
//获取servletContext ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
//空的方法 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.
//这个方法由FrameworkServlet提供实现 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }
initServletBean();方法由FrameworkServlet类来实现的,而这个方法是初始化SpringMvc的上下文环境。从启动的打印日志我们来分析:(这里读取了springmvc.xml还解析了匹配到的类和方法)
信息: Loading XML bean definitions from class path resource [springmvc.xml]
三月 26, 2018 11:19:38 上午 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
信息: Mapped URL path [/**] onto handler 'org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0'
三月 26, 2018 11:19:38 上午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping registerHandlerMethod
信息: Mapped "{[/testExcel],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView com.mmc.excel.TestExcelView.testExcel() throws java.io.UnsupportedEncodingException
三月 26, 2018 11:19:38 上午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping registerHandlerMethod
信息: Mapped "{[/myHandleMethod],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.mmc.hanlemethod.TestHandleMethod.myHandleMethod(org.springframework.web.context.request.WebRequest,org.springframework.ui.Model)
三月 26, 2018 11:19:38 上午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping registerHandlerMethod
信息: Mapped "{[/pets/{petId}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public void com.mmc.helloworld.HelloMatrixVariable.findPet2(java.lang.String,int)
三月 26, 2018 11:19:38 上午 org.springframework.web.servlet.handler.AbstractHandlerMethodMapping registerHandlerMethod
HttpServletBean类的init方法内执行到initServletBean方法,这个方法被FrameworkServlet类覆写。这个方法里其实就一个有效的方法,即initWebApplicationContext();方法。这个方法会调用DispatcherServlet中的onRefresh()方法。然后会执行下面一段内容:
protected void initStrategies(ApplicationContext context) {
//初始化上传文件解析器 initMultipartResolver(context);
//初始化本地解析器 initLocaleResolver(context);
//主题处理器 initThemeResolver(context);
//映射处理器 initHandlerMappings(context);
//处理适配器 initHandlerAdapters(context);
//异常处理器 initHandlerExceptionResolvers(context);
//请求到视图名的翻译器 initRequestToViewNameTranslator(context);
//视图解析器 initViewResolvers(context);
//初始化FlashManager initFlashMapManager(context); }
我理解的简单流程:servlet机制先会去获取web.xml配置文件,获取到servletConfig和servletContext,(关于servletConfig和context的博文)然后创建webApplicationContext,读取springmvc.xml,然后初始化适配器,解析器等。
另外还有一篇博文是讲SpringMvc源码解析的,写的很好,很详细。推荐去看。
书山有路勤为径,学海无涯苦作舟