【聊透SpringMVC】SpringMVC“傳統”方式的啟動過程
打成war包并放入Tomcat等Servlet容器下面運行的,都認為是SpringMVC傳統的啟動方式。
和SpringBoot連用且采用內嵌Web服務器并打成jar包直接運行的,可以認為是SpringMVC現代的啟動方式。
傳統的啟動過程
基于web.xml(配置文件)的方式啟動肯定算傳統的,但由于現在web.xml幾乎已經絕跡,所以就不考慮它了。
與之相對的就是基于編程(寫代碼)的方式啟動,流行于前幾年的SSM(Spring、SpringMVC、MyBatis)中。當然也算傳統的。
在上一篇中講到,通過一個“小橋式”的接口ServletContainerInitializer(Servlet容器初始化器)把Tomcat的啟動和初始化進程帶到了SpringMVC里。
在這個“橋式”接口上可以指定“感興趣”的類或接口,SpringMVC指定的是WebApplicationInitializer(Web應用初始化器)接口,意圖已經很明顯,就是通過這個初始化器接口來完成SpringMVC應用的啟動和初始化。
我們先來看下這個初始化接口,如下圖01:
它只有一個onStartup方法,方法只有一個參數就是ServletContext,這個ServletContext由Tomcat創建好后提供給SpringMVC,SpringMVC在啟動過程中調用這個onStartup方法,在這個方法內完成自身的創建和初始化,還要把Servlet和Filter等注冊到ServletContext里。
這些工作都是SpringMVC要做的,而不是我們要做的,所以SpringMVC肯定已經實現了這個接口,我們查看下類型信息,如下圖02:
我們發現了一個看著很重要的類,就是:
AbstractAnnotationConfigDispatcherServletInitializer
可惜這個類是抽象的,肯定是不能直接用的,但是它里面已經包含了剛剛上面提到的所有完整的啟動邏輯過程。
如果你對SSM很熟悉或Spring的官方文檔看的很熟悉的話,你一定知道這個類是怎么用的。是的,我們需要定義一個類來繼承它即可。
先看下官方文檔上給的用法,如下圖03:
繼承之后,我們需要提供三方面信息,一個是用于注冊到根容器中的類,一個是用于注冊到Servlet容器中的類,一個是核心Servlet的映射URL。
注意,這里說的容器指的是Spring的ApplicationContext這個容器,其中根容器和Servlet容器是父子關系,且在SpringMVC中核心Servlet映射的URL必須是“/”。
下面給出一個我在幾年前為公司搭建框架時的代碼,如下圖04:
這就是以編程的方式來完成SpringMVC的啟動。我們自己定義的這個類就是前文提到的“感興趣”的類。
這個類是不用(或不能)向Spring容器注冊的,因為這個類是感興趣的類,所以Tomcat會從jar包里把它找出來,這樣SpringMVC就拿到了我們定義的這個類。
其實最主要的是這時候根本還沒有Spring容器呢,哈哈,因為Spring容器就是在這個類里才創建出來的,有點意思吧。
其實這個類里包含的內容非常多,我們都可以使用寫代碼的方式來進行配置。下面舉幾個示例。
比如對核心Servlet的一些定制化設置,如下圖05:
比如可以加進去一些自己需要的過濾器,如下圖06:
比如可以對文件上傳進行一些配置,如下圖07:
當然,還可以介入到Spring容器的初始化過程中,進行一些額外的操作,如激活特定的Profile等,如下圖08:
啟動過程中做的事情
其實前面已經說了一些了,這里再來個完整版的,主要包括的事情有:
1、創建根容器。
2、然后把根容器放入ServletContext中。
3、接著創建Servlet容器。
4、然后使用Servlet容器去創建核心Servlet。
5、接著把核心Servlet注冊到ServletContext中。
6、接著再注冊一些過濾器。
下面我們使用幾張圖把這些內容一個個展示一下,需要詳細了解的可以去看看對應的源碼。
創建根容器,可以看到是基于注解的容器類,如下圖09:
將根容器放入ServletContext中,因為ServletContext在應用運行期間一直存在,所以根容器是一個全局性的,也一直存在,如下圖10:
創建Servlet容器,容器類也是基于注解的,和根容器類是一樣的,如下圖11:
使用Servlet容器去創建核心Servlet,如下圖12:
把核心Servlet注冊到ServletContext中,如下圖13:
最后就是注冊一些過濾器了,如下圖14:
號主提示:建議做Java開發且渴望優秀的朋友一定要把這些東西搞清楚。