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

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

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

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

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

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

1,先看webrule的解析規則

  1. digester.addRule(prefix + "web-app/servlet",
  2. new WrapperCreateRule(digester));
  3. digester.addSetNext(prefix + "web-app/servlet",
  4. "addChild",
  5. "org.apache.catalina.Container");
  6.  
  7. digester.addCallMethod(prefix + "web-app/servlet/init-param",
  8. "addInitParameter", 2);
  9. digester.addCallParam(prefix + "web-app/servlet/init-param/param-name",
  10. 0);
  11. digester.addCallParam(prefix + "web-app/servlet/init-param/param-value",
  12. 1);

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

  1. /**
  2. * A Rule that calls the factory method on the specified Context to
  3. * create the object that is to be added to the stack.
  4. */
  5.  
  6. final class WrapperCreateRule extends Rule {
  7.  
  8. public WrapperCreateRule(Digester digester) {
  9. super(digester);
  10. }
  11.  
  12. public void begin(Attributes attributes) throws Exception {
  13. Context context =
  14. (Context) digester.peek(digester.getCount() - 1);
  15. Wrapper wrapper = context.createWrapper();
  16. digester.push(wrapper);
  17. if (digester.getDebug() > 0)
  18. digester.log("new " + wrapper.getClass().getName());
  19. }
  20.  
  21. public void end() throws Exception {
  22. Wrapper wrapper = (Wrapper) digester.pop();
  23. if (digester.getDebug() > 0)
  24. digester.log("pop " + wrapper.getClass().getName());
  25. }
  26.  
  27. }

看到關鍵程式碼是建立了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類,那莫就剩下了自己的自定義類

  1. package org.springframework.samples.mvc.config;
  2.  
  3. import javax.servlet.Filter;
  4.  
  5. import org.springframework.web.filter.DelegatingFilterProxy;
  6. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
  7.  
  8. /**
  9. * Initialize the Servlet container. This class is detected by the Servlet
  10. * container on startup.
  11. */
  12. public class MvcShowcaseAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
  13.  
  14. @Override
  15. protected Class<?>[] getRootConfigClasses() {
  16. return new Class[] { RootConfig.class };
  17. }
  18.  
  19. @Override
  20. protected Class<?>[] getServletConfigClasses() {
  21. return new Class[] { WebMvcConfig.class };
  22. }
  23.  
  24. @Override
  25. protected String[] getServletMappings() {
  26. return new String[] { "/" };
  27. }
  28.  
  29. @Override
  30. protected Filter[] getServletFilters() {
  31. return new Filter[] { new DelegatingFilterProxy("csrfFilter") };
  32. }
  33.  
  34. }

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

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

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

建立了dispatcherServlet物件,然後將物件新增到standardcontext中去,

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

還有

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

至此物件建立完成,還沒解析的有servletmaping標籤,和初始化引數等吧,

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