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感到迷惑呢