tomcat與springmvc 結合 之---第16篇 servlet如何解析成員變數和DispatcherServlet如何解析
writedby 張豔濤,用了兩個星期將深入刨析tomcat看完了,那麼接下來該看什麼呢?真是不知道,知識這東西上一個月看的jvm,鎖.多執行緒併發 又都忘了....
tomcat學完,我打算看springmvc因為,spring本質就是一個servlet, 叫DispatcherServlet,那麼倆者聯絡緊密,打算結合二者,進行學習
昨天看了一天發現spring原始碼,看起來比tomcat要難,因為springmv太雜了
以前看過知道web.xml中的<servlet>標籤解析,那麼遇到了
<servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>com.qcc.study.servlet02.LoginServlet</servlet-class> <!-- 配置Servlet初始化引數 --> <init-param> <param-name>initParam</param-name> <param-value>qcc</param-value> </init-param> <!-- Web容器啟動時就載入並例項化該Servlet --> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> </servlet>
以上的引數該如何解析呢?這個init-param目的就是要給成員變數初始化值,看如何使用
package com.qcc.study.servlet02; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class LoginServlet extends HttpServlet { 成員變數1 initParam = null;
成員變數2=null;
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //獲取servlet初始化引數: String initParam = getServletConfig().getInitParameter("initParam"); System.out.println("initParam: ---->" + initParam); }
那麼可以看到,
<init-parm>配置在<servlet>標籤中,用來初始化當前的Servlet的,屬於當前Servlet的配置,因此存放在 servletConfig物件中;
通過getServletConfig().getInitParameter("initParam")的方式獲取;
如果通過原始碼來看webruleset中對"web-app/servlet/init-param"解析
看addInitParameter StandardWrapper中
可以看到其實引數以hashmap的方法來組織成鍵值對,如果使用的時候,實際上是從wrapper容器中取得的,和servlet.class沒關係
如果在形成的servlet物件的成員變數賦值寫在init()方法裡面,最後形成的servlet物件的成員變數就是完全體了,這其實就是dispatchServlet的做法
先看一個dispatchservlet的配置檔案web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>springmvcFirst</display-name> <!-- springMVC前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation配置springmvc載入的配置檔案(配置處理器、對映器等) 如果不配置contextConfigLocation,預設載入的是/WEB-INF/servlet名稱-servlet.xml(springmvc-servlet.xml) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- url-pattern:*.action的請交給DispatcherServlet處理。 --> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app>
看這其實是給servlet設值,那麼看dispatchservlet的成員變數
重點看FrameworkServlet,是dispatcherServlet的父類, 其中有一個成員變數叫contextConfigLocation,對應了標籤中的引數名
那麼在哪裡賦值的呢?
在HttpServletBean的init()方法裡面
其中init(servletConfig)的呼叫邏輯
GenericServlet===>
public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); }
本類的this.init(),其實這裡使用了模板方法,這個this是指的dispatchservlet物件,
public void init() throws ServletException { }
所以呼叫的init()方法在HttpServletBean 中
public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } // Set bean properties from init parameters. try { PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); 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) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); throw ex; } // Let subclasses do whatever initialization they like. initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } }
這個方法解析了wrapper中的屬性,重點看config就是StandardWrapper,呼叫了上文貼上的獲取parameter的方法了
最後能看到BW是通過反射來實現屬性的注入的
另外說一點,這servlet類的設計,使用了模板方法,是在GenericServlet中的
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
那麼看tomcat的呼叫
這個servlet物件就是dispatchservelet,這樣子類呼叫父類的GenericServlet的init(servletconfig)方法,接著呼叫this(這個this是子類disptacherservlet物件,可以sout(this)驗證).init()方法,
整個dispatcherservlet的呼叫思路就弄清楚了