本篇文章為大家展示了如何進行SpringMVC的DispatcherServlet源碼分析,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
成都創(chuàng)新互聯(lián)主營安慶網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP開發(fā)公司,安慶h5微信平臺小程序開發(fā)搭建,安慶網(wǎng)站營銷推廣歡迎安慶等地區(qū)企業(yè)咨詢
SpringMVC核心就是DispatcherServlet,所有得請求都會轉(zhuǎn)發(fā)到DispatcherServlet,然后再通過DispatcherServlet執(zhí)行具體得控制層(Handler)返回ModelAndView給客戶端視圖展示。
// 3. 將我們的DispatcherServlet 注入到 serlvet容器中ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(app));// 4.填寫url路徑映射dynamic.addMapping("/");
DispatcherServlet其實就是一個Servlet類,無非就是包裝一層,通過url能夠映射找到我們得SpringMvc中定義得請求方法。
源代碼分析:
類的集成關(guān)系
DispatcherServlet繼承FrameworkServlet繼承HttpServlet
面向基本上思想 重寫 先走父類 ,在走子類。
得出答案:先看HttpServlet在找到我們最后的子類
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.processRequest(request, response); }
關(guān)系:DispatcherServlet繼承FrameworkServlet繼承HttpServlet
流程執(zhí)行關(guān)系:
HttpServlet service方法 判斷請求方法的類型
FrameworkServlet doService
DispatcherServlet doService
在servlet初始化階段會調(diào)用其init方法,所以我們首先要查看在DispatcherServlet中是否重寫了init方法。我們在其父類HttpServletBean中找到該方法
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { .... public final void init() throws ServletException { if (this.logger.isDebugEnabled()) { this.logger.debug("Initializing servlet '" + this.getServletName() + "'"); } //解析init-param并封裝至pvs中PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { //將當(dāng)前的servlet類轉(zhuǎn)換為一個BeanWrapper,從而能夠以Spring的方式來對init-param的值進行注入BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext()); //注冊自定義屬性編輯器,一旦遇到Resource類型的屬性會使用ResourceEditor進行解析bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment())); //空實現(xiàn),留給子類覆蓋this.initBeanWrapper(bw); //屬性注入bw.setPropertyValues(pvs, true); } catch (BeansException var4) { if (this.logger.isErrorEnabled()) { this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4); } throw var4; } } //留給子類擴展this.initServletBean(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully"); } } .... }
DispatcherServlet的初始化過程主要是通過將當(dāng)前的Servlet類型實例轉(zhuǎn)換為BeanWrapper類型實例,以便使用Spring中提供的注入功能進行對應(yīng)屬性的注入。
我們看下servletBean的初始化,HttpServletBean其父類FrameworkServlet覆蓋了它的initServletBean函數(shù),如下:
protected final void initServletBean() throws ServletException { this.getServletContext().log("Initializing Spring FrameworkServlet '" + this.getServletName() + "'"); if (this.logger.isInfoEnabled()) { this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization started"); } //計時器,統(tǒng)計初始化的執(zhí)行時間long startTime = System.currentTimeMillis(); try { //關(guān)鍵的初始化邏輯委托給了這個方法this.webApplicationContext = this.initWebApplicationContext(); //設(shè)計為子類覆蓋this.initFrameworkServlet(); } catch (RuntimeException | ServletException var5) { this.logger.error("Context initialization failed", var5); throw var5; } if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms"); } }
initWebApplicationContext函數(shù)主要工作就是創(chuàng)建或者刷新WebApplicationContext實例并對servlet功能所使用的變量進行初始化
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { //context實例在構(gòu)造函數(shù)中被注入wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac; if (!cwac.isActive()) { if (cwac.getParent() == null) { cwac.setParent(rootContext); } //刷新上下文環(huán)境this.configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { //根據(jù)contextAttribute屬性加載webApplicationContextwac = this.findWebApplicationContext(); } if (wac == null) { wac = this.createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { this.onRefresh(wac); } if (this.publishContext) { String attrName = this.getServletContextAttributeName(); this.getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; }
刷新方法onRefresh
protected void onRefresh(ApplicationContext context) { this.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);//初始化重定向數(shù)據(jù)管理器
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... try { try { ... //通過url路徑地址去查找控制層類方法,如果沒有找到的化,直接返回404mappedHandler = this.getHandler(processedRequest); .... HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); .... if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); .... mappedHandler.applyPostHandle(processedRequest, response, mv); .... }
private ListhandlerMappings;
mappedHandler = this.getHandler(processedRequest);
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; }
/** * 請求方法前置攔截,如果返回true 表示會執(zhí)行到目標(biāo)方法(請求方法) 如果返回false的情況下 則不會執(zhí)行目標(biāo)方法。 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getParameter("token"); System.out.println(">>>>token<<<<:" + token); if (StringUtils.isEmpty(token)) { response.setStatus(500); response.getWriter().print(" token is null"); return false; } // 執(zhí)行我們的請求方法return true; }
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
執(zhí)行目標(biāo)方法:
@RequestMapping("/pageIndex") public String pageIndex() { System.out.println(">>>pageIndex<<<<"); return "pageIndex"; }
mappedHandler.applyPostHandle(processedRequest, response, mv);
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("<<>>>"); // 請求之后執(zhí)行。}
1.執(zhí)行doDispatch
2.調(diào)用getHandler方法獲取請求目標(biāo)的方法 也就是 請求url映射路徑對應(yīng)的控制層具體的方法
handlerMappings的作用查找控制器位置,比如xml和注解方式。
3.調(diào)用getHandlerAdapter獲取控制層適配器 RequestMappingHandlerAdapter
4.執(zhí)行攔截器前置方法 preHandle() 如果返回為true的話
5.執(zhí)行實際請求目標(biāo)方法 返回modeAndView對象
6.執(zhí)行攔截器PostHandle()方法
7.設(shè)置渲染視圖層內(nèi)容
8.執(zhí)行攔截器afterCompletion方
SpringMVC控制層容器初始化
HttpServletBean init ()方法
FrameworkServlet initServletBean方法→ initWebApplicationContext();
DispatcherServlet onRefresh方法→ initStrategies()方法
protected void onRefresh(ApplicationContext context) { this.initStrategies(context); }
當(dāng)我們servlet容器初始化的時候初始化
this.initHandlerMappings(context);
上述內(nèi)容就是如何進行SpringMVC的DispatcherServlet源碼分析,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。