上一篇講了Spring MVC中HttpServletBean的源碼,本篇會順著類的繼承結構來講一下HttpServletBean的子類FrameworkServlet。所有源碼都是基于spring-framework-4.3.5.RELEASE
前篇講的HttpServletBean功能上還沒有涉及到和Spring MVC框架有關的東西,而FrameworkServlet從名字上就可以推斷出,它已經和框架緊密結合在一起了。簡單來說,它有下面這些特性和作用:
它是Spring web framework的一個基礎servlet,提供了和Spring ApplicationContext的集成(關于ApplicationContext會在以后的文章中詳細解釋),它管理著一個WebApplicationContext的實例,會發布一個事件消息在處理完一個請求之后
它的子類必須實現doService方法來處理接受到的請求
它會檢測在web.xml中的servlet參數配置中是否存在contextClass,如果存在的話,就會實例化指定的context class,如果不存在就會使用默認的XmlWebApplicationContext
接下來,源碼伺候
public abstract class FrameworkServlet
extends HttpServletBean implements ApplicationContextAware {
FrameworkServlet除了繼承了HttpServletBean還實現了ApplicationContextAware接口,這個接口中定義了一個setApplicationContext的方法,這個方法留下了一個入口以便于框架在之后可以通過它setApplicationContext的實例。
接下來看看這個類中一些關鍵的靜態及成員變量
public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
public String getNamespace() {
return (this.namespace != null ?
this.namespace : getServletName() + DEFAULT_NAMESPACE_SUFFIX);
}
這里定義了一個常量DEFAULT_NAMESPACE_SUFFIX, 以及一個getNameSpace的方法,getNameSpace會返回你在web.xml中配置的servlet-name加上"-servlet",這個namespace會在之后application context加載spring配置文件時候用到,比如你給servlet取名叫MySpringServlet,那么當Spring初始化的時候,會去尋找名為/WEB-INF/MySpringServlet-servlet.xml的配置文件。
public static final Class<?> DEFAULT_CONTEXT_CLASS =
XmlWebApplicationContext.class;
private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
默認的applicationContext類,即XmlWebApplicationContext
這個類中最重要的一個成員方法是initServletBean, 這個方法是在父類HttpServletBean中的一個鉤子方法(hook method), 也就是定義是在父類中,但是實現是在子類。如果你看了上一篇文章就會知道在父類init的時候會調用這個鉤子方法。
這個方法其實非常簡單
489行 調用initWebApplicationContext方法初始化一個WebApplicationContext,現在大家知道平時經常提到的application context是在哪里生成的了吧,沒錯,就是在這里。
490行 調用initFrameworkServlet方法,這個方法又是一個鉤子方法,在當前類里只有一個空的實現,真正的實現是在子類DispatcherServlet中。
接下來我們著重看一下initWebApplicationContext方法
523-524行 嘗試從ServletContext中尋找根上下文(root context),如果你在web.xml中定義過ContextLoaderListener,那么Spring framework就會先初始化一個根的application context并設置到ServletContext的一個attribute中,如果沒有定義,那這一步就會得到到一個null,不過沒有影響。
527-538行 在代碼段開始會去判斷當前對方的一個webApplicationContext成員變量是不是有值,因為FrameworkServlet中有一個構造函數是允許傳入一個現成的applicationContext,所以如果存在的話就不需要再new一個applicationContext了。
539-541行 如果wac變量仍然為null,就會嘗試在ServletContext中去查找是否存在一個已經初始化過的WebApplicationContext.
542-544行 調用createWebApplicationContext方法(下文會繼續深入這個方法),這里就是真正去創建一個新的WebApplicationContext的地方了,并且會把上面獲取到的rootContext(可能為null)作為參數傳入。
546-548行 可以看到有一個變量this.refreshEventReceived去標志類中的onRefresh方法是不是已經被調用過,如果沒有,那就調用onRefresh
550-557行 通過變量this.publishContext來決定是不是要把初始化后的WebApplicationContext設置到ServletContext的attrbiute里去。
相信大家現在對FrameworkServlet這個class的職責有了更加深入的理解,Spring中最重要的applicationContext的初始化就是它來干的。
出于方便大家閱讀和理解(源碼這東西本來消化起來就不容易),我會把createWebApplicationContext方法的解釋放到下一篇文章里詳細說明。