springmvc學習指南 之—第27篇 spring如何實現servlet3.0無web.xml 配置servlet對象的

writedby 張艷濤 基於web.xml配置,有人說麻煩,tomcat給按照servlet3.0,實現了基於註解@WebServlet,有人說springmvc的springmvc.xml配置麻煩

於是有了springboot,如果讓我問,這好嗎?  我是不喜歡的,如果你看了深入刨析tomcat後,你就知道使用註解是多麼噁心的事情了,打個比方,如果給你一個

宇宙飛船,你不會開,那麼給你兩種途經,一個是基於飛船的各個系統部件的說明,告訴你這個是開關,開關在哪裡,這個是剎車,剎車在哪裡;而另外一種是

給給開關貼一個標籤,給剎車一個標籤,給飛船一個掃描儀,然後讓飛船自己運行;多麼智慧,問題是飛船壞了不會修呢. 我是不喜歡這種複雜的簡單,所以

現在只能從xml的配置來 學習註解,現在開始看spring,被逼的要從spirng2.5開始看,問題是資料太少了….

 我是一個活在舊時代的sha子,時間越久,越發現別人都在進步,而自己止步不前,一個時代的人終究會在自己的籠子里做困獸之鬥,正如sporty做的調查,35歲後的聽歌喜好,不會接受35之後的歌曲了. 就這樣吧,活的真慘

 

xml時代,無配置時代的springboot,可是我有點選擇嗎?沒有

xml時代,tomcat是如何解析<servlet>標籤的呢?

1,先看webrule的解析規則

        digester.addRule(prefix + "web-app/servlet",
                         new WrapperCreateRule(digester));
        digester.addSetNext(prefix + "web-app/servlet",
                            "addChild",
                            "org.apache.catalina.Container");

        digester.addCallMethod(prefix + "web-app/servlet/init-param",
                               "addInitParameter", 2);
        digester.addCallParam(prefix + "web-app/servlet/init-param/param-name",
                              0);
        digester.addCallParam(prefix + "web-app/servlet/init-param/param-value",
                              1);

分析,先創建一個規則rule,這個規則會在遇到遇到web-app/servlet標籤的時候,執行規則的begin,再次遇到的時候會執行end

/**
 * A Rule that calls the factory method on the specified Context to
 * create the object that is to be added to the stack.
 */

final class WrapperCreateRule extends Rule {

    public WrapperCreateRule(Digester digester) {
        super(digester);
    }

    public void begin(Attributes attributes) throws Exception {
        Context context =
            (Context) digester.peek(digester.getCount() - 1);
        Wrapper wrapper = context.createWrapper();
        digester.push(wrapper);
        if (digester.getDebug() > 0)
            digester.log("new " + wrapper.getClass().getName());
    }

    public void end() throws Exception {
        Wrapper wrapper = (Wrapper) digester.pop();
        if (digester.getDebug() > 0)
            digester.log("pop " + wrapper.getClass().getName());
    }

}

看到關鍵程式碼是創建了standwrapper,推進去了digester棧中,

2,執行standardcontext的addChild方法將wrapper加入其中,接著,將servlet裝入context的children成員變數中


上邊的解析非常清晰,如果遇到不懂的標籤,自己看下webruleset的規則,秒懂了,而現在呢?我想看spring如何實現了servlet3.0的無xml配置dispatcherservlet的?

真是噁心,看了1個小時才看懂點,下面將分析過程說明如下

servlet為了實現無xml,那麼就得基於註解,就得在某個類中使用註解,現在是有兩種實現方法的

其一是使用@WebServlet(name=”xxxx”,url=”xxx”)

其二是使用ServletContainerInitializer 介面,原理是,在tomcat等servlet容器啟動的時候,會去lib包下掃描springmvc.x.y.z的jar包內的所有類,如果類是ServletContainerInitializer 介面的實現那麼就執行這個實現類的onStartup方法.那麼我們來就spirng實現了

那末會有幾個實現呢?答案是6個

  

這些類有的在webmvc,web,security-web,自定義繼承AbstractAnnotationConfigDispatcherServletInitializer類,等包中

那麼就需要篩選,排除interface 和abstract類,那莫就剩下了自己的自定義類

package org.springframework.samples.mvc.config;

import javax.servlet.Filter;

import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * Initialize the Servlet container. This class is detected by the Servlet
 * container on startup.
 */
public class MvcShowcaseAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { RootConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebMvcConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { new DelegatingFilterProxy("csrfFilter") };
    }

}

接下來就是執行這個MvcShowcaseAppInitializer,的  initializer.onStartup(servletContext);

他自己沒有onstartup方法,看他的父類AbstractDispatcherServletInitializer

那麼還是挑重點的講,進入registerDispatcherServlet

創建了dispatcherServlet對象,然後將對象添加到standardcontext中去,

看這個servletContext.addServlet(),就是tomcat8.5的程式碼了,

還有

能看到將也是創建wrapper,設置wrapper屬性,然後交給stardardcontext.addChild(wrapper)給children的成員變數

至此對象創建完成,還沒解析的有servletmaping標籤,和初始化參數等吧,

這麼看來,其實解析一個無xml配置,真的好費勁呢,所以對能否學好springboot感到迷惑呢