spring mvc的零xml配置原理

spring mvc的零xml配置原理

在tomcat啟動(dòng)的時(shí)候咆爽,會(huì)調(diào)用到一個(gè)類脆丁,叫StandardContext音榜,這里會(huì)讀取我們配置的web.xml文件蔚鸥,所以可以簡(jiǎn)單的理解為“tomcat啟動(dòng)的時(shí)候默認(rèn)會(huì)調(diào)用web.xml”惜论。

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param> 

在web.xml中,最開(kāi)始我們?cè)谂渲胢vc的時(shí)候都會(huì)配置這兩個(gè)東西止喷。ContextLoaderListener(spring中的類)實(shí)現(xiàn)了ServletContextListener(servlet中的類)馆类,ServletContextListener能夠監(jiān)聽(tīng)到servlet的生命周期,而一個(gè)web應(yīng)用啟動(dòng)的時(shí)候就只有1個(gè)servlet弹谁,因此相當(dāng)于監(jiān)聽(tīng)了整個(gè)web應(yīng)用乾巧。web啟動(dòng)后,會(huì)觸發(fā)ServletContextEvent事件预愤,此時(shí)就會(huì)調(diào)用ContextLoaderListener中的contextInitialized方法沟于,這個(gè)方法會(huì)調(diào)用initWebApplicationContext,返回一個(gè)WebApplicationContext鳖粟,在這個(gè)方法中社裆,會(huì)加載在web.xml中配置的classpath。因此在web.xml中配置的這段實(shí)際上的作用是“tomcat來(lái)初始化一個(gè)spring環(huán)境”向图。

public void contextInitialized(ServletContextEvent event) {
    this.initWebApplicationContext(event.getServletContext());
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    ...
    String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);//"contextConfigLocation"(設(shè)置配置文件的路徑名)
}

那么如果我們想不用xml配置泳秀,需要我們自己來(lái)初始化spring環(huán)境标沪,在一個(gè)spring項(xiàng)目中,我們初始化spring的方式是嗜傅。

@ComponentScan("com.bafan.spring.dependencies")
public class AppConfig {
}

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

所以思路就是需要我們自己new一個(gè)ApplicationContext金句,然后需要tomcat在啟動(dòng)的時(shí)候能調(diào)用到它。

web.xml中另一個(gè)很重要的需要配置的點(diǎn)就是攔截器吕嘀,在使用web.xml的時(shí)候违寞,配置姿勢(shì)如下面所示。

<servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <!-- 此處可以可以配置成*.do偶房,對(duì)應(yīng)struts的后綴習(xí)慣 -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

如果不通過(guò)web.xml的方式能夠讓上面的代碼別調(diào)用趁曼,mvc官方文檔中寫,可以實(shí)現(xiàn)WebApplicationInitializer棕洋,然后重寫onStartup方法挡闰。

/**
 * mvc如何實(shí)現(xiàn)0xml配置
 * onStartup方法,tomcat是如何能調(diào)用到的
 */
public class BafanWebApplication implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        System.out.println("tomcat------init---------");
        //spring環(huán)境初始化
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(AppConfig.class);
        applicationContext.setServletContext(servletContext);
        applicationContext.refresh();

        //web環(huán)境初始化(servlet的配置)
        DispatcherServlet servlet = new DispatcherServlet(applicationContext);
        ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
        registration.addMapping("*.do");
        registration.setLoadOnStartup(1);
    }
}

在tomcat啟動(dòng)的時(shí)候掰盘,會(huì)調(diào)用到我們重寫的onStartup方法摄悯,在這個(gè)方法中,我們初始化了spring的環(huán)境愧捕,因此就不用xml的方式初始spring的環(huán)境了奢驯,同時(shí)也初始化了web的環(huán)境。寫了這幾行代碼就可以不用配置web.xml了次绘。

為什么我們實(shí)現(xiàn)了WebApplicationInitializer tomcat就可以調(diào)用到我們重寫的方法了呢瘪阁?

  1. WebApplicationInitializer是在org.springframework.web這個(gè)包下面的,也就是說(shuō)這個(gè)接口是spring寫的断盛,點(diǎn)到這個(gè)jar包下罗洗。
  2. 它的根目錄中的/META-INF/services有一個(gè)文件,文件名是javax.servlet.ServletContainerInitializer钢猛,文件里面寫著org.springframework.web.SpringServletContainerInitializer。根據(jù)servlet的規(guī)范轩缤,tomcat和spring都遵守這個(gè)規(guī)范命迈,tomcat啟動(dòng)的時(shí)候會(huì)調(diào)用這個(gè)方法(servlet的規(guī)定)。
  3. 這個(gè)方法的上面火的,加了一個(gè)@HandlesTypes(WebApplicationInitializer.class)的注解壶愤,@Nullable Set<Class<?>> webAppInitializerClasses的入?yún)⒅校绻覀冏约簩?shí)現(xiàn)了WebApplicationInitializer這個(gè)接口的話馏鹤,這個(gè)入?yún)⒅袝?huì)拿到我們所有實(shí)現(xiàn)了這個(gè)接口類征椒,然后循環(huán)調(diào)用里面的onStartup方法。
for (WebApplicationInitializer initializer : initializers) {
    initializer.onStartup(servletContext);
}

我們可以自己模擬一下這個(gè)過(guò)程

1. 在根目錄下創(chuàng)建一個(gè)/META-INF/services/javax.servlet.ServletContainerInitializer這個(gè)文件湃累,里面寫com.bafan.spring.web.test.BafanServletContainerInitializer
2. 
@HandlesTypes(A.class)
public class BafanServletContainerInitializer implements ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        System.out.println("執(zhí)行了");
    }

}
3. 啟動(dòng)tomcat勃救,這時(shí)候set會(huì)傳進(jìn)來(lái)B和C(都實(shí)現(xiàn)了A這個(gè)接口)碍讨。

PS:

在代碼中引入
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-catalina</artifactId>
    <version>8.5.43</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>8.5.45</version>
</dependency>

/**
 * 如何使用一個(gè)jar包的方式用main方法來(lái)啟動(dòng)tomcat
 */
public class TomcatServer {

    public static void main(String[] args) {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8080);
        tomcat.addWebapp("/", "/Users/maxiaojun/bafan/tomcat");
        try {
            tomcat.start();
            tomcat.getServer().await();
        } catch (LifecycleException e) {
            e.printStackTrace();
        }
    }

}
這樣就可以在代碼中使用一個(gè)方法來(lái)啟動(dòng)tomcat,感覺(jué)很高大尚蒙秒。

一個(gè)mvc項(xiàng)目勃黍,如果什么都不配置的話

@RequestMapping("/query.do")
@ResponseBody
public Map<String, String> query() {
    System.out.println("query controller");
    Map<String, String> map = new HashMap<String, String>();
    map.put("xxx", "xxxx");
    return map;
}
這行代碼會(huì)報(bào)500的錯(cuò)誤,因?yàn)閙vc默認(rèn)不知道咋對(duì)Map(對(duì)象也一樣)進(jìn)行解析晕讲,所以需要我們配置一下覆获,告訴mvc要用fastjson來(lái)解析
@Configuration
@ComponentScan("com.bafan.spring.web")
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new FastJsonHttpMessageConverter());
    }

}
實(shí)現(xiàn)WebMvcConfigurer,重寫configureMessageConverters方法瓢省,然后加一下fastjson解析器就ok了弄息。

思考方式:

  1. tomcat啟動(dòng)的時(shí)候是怎么初始化的spring環(huán)境?
  2. tomcat初始化web環(huán)境的時(shí)候有哪些比較重要的配置勤婚?
  3. 為什么實(shí)現(xiàn)了WebApplicationInitializer之后疑枯,里面的onStartUp方法就能別調(diào)用到?
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蛔六,一起剝皮案震驚了整個(gè)濱河市荆永,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌国章,老刑警劉巖具钥,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異液兽,居然都是意外死亡骂删,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門四啰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宁玫,“玉大人,你說(shuō)我怎么就攤上這事柑晒∨繁瘢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵匙赞,是天一觀的道長(zhǎng)佛掖。 經(jīng)常有香客問(wèn)我,道長(zhǎng)涌庭,這世上最難降的妖魔是什么芥被? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮坐榆,結(jié)果婚禮上拴魄,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好匹中,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布夏漱。 她就那樣靜靜地躺著,像睡著了一般职员。 火紅的嫁衣襯著肌膚如雪麻蹋。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天焊切,我揣著相機(jī)與錄音扮授,去河邊找鬼。 笑死专肪,一個(gè)胖子當(dāng)著我的面吹牛刹勃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嚎尤,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼荔仁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了芽死?” 一聲冷哼從身側(cè)響起乏梁,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎关贵,沒(méi)想到半個(gè)月后遇骑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體炉媒,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锋喜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仆嗦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炭剪。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡练链,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奴拦,到底是詐尸還是另有隱情媒鼓,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布粱坤,位于F島的核電站隶糕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏站玄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一濒旦、第九天 我趴在偏房一處隱蔽的房頂上張望株旷。 院中可真熱鬧,春花似錦、人聲如沸晾剖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)齿尽。三九已至沽损,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間循头,已是汗流浹背绵估。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卡骂,地道東北人国裳。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像全跨,于是被迫代替她去往敵國(guó)和親缝左。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容