很好的一篇文章,拿到博客和大家共享一下

(转)0Spring中MVC框架的底层实现


Written by Tony Jiang @ 20120119

Spring中的MVC

Spring MVC的流程

Spring的Sample这里就不讲了,大家自己上网google

Spring 在Web环境下的启动

ServletContextListener。

                (问题: ContextListener如何启动? 随着web容器启动而启动?是单线程的?线程安全的?)

ContextListener是随着Tomcat的启动而启动,并且只启动这一次,为整个WebContext的启动做准备。

                Spring在Web环境下启动的监听器是:


1. public class ContextLoaderListener extends ContextLoader implements ServletContextListener {  
2. /**
3.      * Initialize the root web application context.
4.      */  
5. public void contextInitialized(ServletContextEvent event) {  
6. this.contextLoader = createContextLoader();  
7. if (this.contextLoader == null) {  
8. this.contextLoader = this;  
9.         }  
10. this.contextLoader.initWebApplicationContext(event.getServletContext());  
11.     }

其中WebApplication的上下文在ContextLoader中初期化


1. /**
2.      * Initialize Spring's web application context for the given servlet context,
3.      * using the application context provided at construction time, or creating a new one
4.      * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
5.      * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
6.      * @param servletContext current servlet context
7.      * @return the new WebApplicationContext
8.      * @see #ContextLoader(WebApplicationContext)
9.      * @see #CONTEXT_CLASS_PARAM
10.      * @see #CONFIG_LOCATION_PARAM
11.      */  
12. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {  
13. try {  
14. // Store context in local instance variable, to guarantee that  
15. // it is available on ServletContext shutdown.  
16. if (this.context == null) {  
17. this.context = createWebApplicationContext(servletContext);  
18.             }


最后的启动委托给XmlWebApplicationContext

这个类中使用了大量的模板设计模式!!

最终的容器启动和我们编程式启动Spring类同

入口的DispatchServlet

1. /**
2.      * Loads the bean definitions via an XmlBeanDefinitionReader.
3.      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
4.      * @see #initBeanDefinitionReader
5.      * @see #loadBeanDefinitions
6.      */  
7. @Override  
8. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
9. // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
10. new XmlBeanDefinitionReader(beanFactory);  
11.   
12. // Configure the bean definition reader with this context's  
13. // resource loading environment.  
14. this.getEnvironment());  
15. this);  
16. new ResourceEntityResolver(this));  
17.   
18. // Allow a subclass to provide custom initialization of the reader,  
19. // then proceed with actually loading the bean definitions.  
20.         initBeanDefinitionReader(beanDefinitionReader);  
21.         loadBeanDefinitions(beanDefinitionReader);  
22.     }

DispatchServlet的初期化和生成,我认为不是由Spring容器负责的,应该是由Web容器自己管理的。可以参考《How tomcat works》这本书

DispatchServlet的init方法在父类的父类的HttpServletBean中

是一个final方法哦


1. public final void init() throws ServletException {  
2. if (logger.isDebugEnabled()) {  
3. "Initializing servlet '" + getServletName() + "'");  
4.         }  
5.   
6. // Set bean properties from init parameters.  
7. try {  
8. new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);  
9. this);  
10. new ServletContextResourceLoader(getServletContext());  
11. class, new ResourceEditor(resourceLoader, this.environment));  
12.             initBeanWrapper(bw);  
13. true);  
14.         }  
15. catch (BeansException ex) {  
16. "Failed to set bean properties on servlet '" + getServletName() + "'", ex);  
17. throw ex;  
18.         }  
19.   
20. // Let subclasses do whatever initialization they like.  
21.         initServletBean();  
22.   
23. if (logger.isDebugEnabled()) {  
24. "Servlet '" + getServletName() + "' configured successfully");  
25.         }  
26.     }

 

真正的servlet的初期化在子类中执行,又是模板模式~~~

于是我们在子类的FrameworkServlet中看到


1. /**
2.      * Overridden method of {@link HttpServletBean}, invoked after any bean properties
3.      * have been set. Creates this servlet's WebApplicationContext.
4.      */  
5. @Override  
6. protected final void initServletBean() throws ServletException {  
7. "Initializing Spring FrameworkServlet '" + getServletName() + "'");  
8. if (this.logger.isInfoEnabled()) {  
9. this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");  
10.         }  
11. long startTime = System.currentTimeMillis();  
12.   
13. try {  
14. this.webApplicationContext = initWebApplicationContext();  
15.             initFrameworkServlet();  
16.         }  
17. catch (ServletException ex) {  
18. this.logger.error("Context initialization failed", ex);  
19. throw ex;  
20.         }  
21. catch (RuntimeException ex) {  
22. this.logger.error("Context initialization failed", ex);  
23. throw ex;  
24.         }  
25.   
26. if (this.logger.isInfoEnabled()) {  
27. long elapsedTime = System.currentTimeMillis() - startTime;  
28. this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +  
29. " ms");  
30.         }  
31.     }

 

接下来最后将自己sevlet对应上具体的ServletContext

先回顾一下Servlet的生存周期

Servlet的init方法是在容器的启动中被启动,只执行这一次。

那就意味着,Servlet的所需要的资源,内存空间,instance的预实例化都要在init内完成。

作为Spring Servlet的init,那么相对应ServletName -servlet.xml中所有的定义类都必须在init中被成功初期化。

我们拿一个简单ServletName -servlet.xml来举例

1. 1 <?xml version="1.0" encoding="UTF-8" ?>  
2. >  
3.  3   
4. <beans>  
5.  5   
6. <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
7. <property name="prefix" value="/WEB-INF/jsp/" />  
8. <property name="suffix" value=".jsp" />  
9. </bean>  
10. 10   
11. 11     <bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">  
12. 12         <property name="mappings">  
13. 13             <props>  
14. 14                 <prop key="/hello.do">helloController</prop>  
15. 15             </props>  
16. 16         </property>  
17. 17     </bean>  
18. 18   
19. 19     <bean id="helloController" class="com.ideawu.HelloController">  
20. 20         <!--  
21. 21         <property name="helloManager" ref="helloManager" />  
22. 22         -->  
23. 23     </bean>  
24. 24   
25. 25 </beans>

 

其中包括viewResolver(采用何种视图模板),HandlerMapping(采用何种http拦截器),Controller(对应每种http请求采用何种控制器)。

所有的这些,都是通过Spring容器本身进行加载的。

DispatchServlet中这些资源的加载是在本身的initStrategies方法内执行(通过父类模板方法的调用)


1. /**
2.      * Initialize the strategy objects that this servlet uses.
3.      * <p>May be overridden in subclasses in order to initialize further strategy objects.
4.      */  
5. protected void initStrategies(ApplicationContext context) {  
6.         initMultipartResolver(context);  
7.         initLocaleResolver(context);  
8.         initThemeResolver(context);  
9.         initHandlerMappings(context);  
10.         initHandlerAdapters(context);  
11.         initHandlerExceptionResolvers(context);  
12.         initRequestToViewNameTranslator(context);  
13.         initViewResolvers(context);  
14.         initFlashMapManager(context);  
15.     }

 

关于HandlerMapping

                handlerMaper是一个单例的(相对于一个JVM而言)的ArrayList

                它的初期化在DispatchServlet中


1. /**
2.      * Initialize the HandlerMappings used by this class.
3.      * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
4.      * we default to BeanNameUrlHandlerMapping.
5.      */  
6. private void initHandlerMappings(ApplicationContext context) {  
7. this.handlerMappings = null;  
8.   
9. if (this.detectAllHandlerMappings) {  
10. // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.  
11.             Map<String, HandlerMapping> matchingBeans =  
12. class, true, false);  
13. if (!matchingBeans.isEmpty()) {  
14. this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());  
15. // We keep HandlerMappings in sorted order.  
16. this.handlerMappings);  
17.             }  
18.         }  
19. else {  
20. try {  
21. class);  
22. this.handlerMappings = Collections.singletonList(hm);  
23.             }  
24. catch (NoSuchBeanDefinitionException ex) {  
25. // Ignore, we'll add a default HandlerMapping later.  
26.             }  
27.         }  
28.   
29. // Ensure we have at least one HandlerMapping, by registering  
30. // a default HandlerMapping if no other mappings are found.  
31. if (this.handlerMappings == null) {  
32. this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);  
33. if (logger.isDebugEnabled()) {  
34. "No HandlerMappings found in servlet '" + getServletName() + "': using default");  
35.             }  
36.         }  
37.     }


 

它的被执行是在DispatchServlet中的doService中


1. /**
2.      * Return the HandlerExecutionChain for this request.
3.      * <p>Tries all handler mappings in order.
4.      * @param request current HTTP request
5.      * @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
6.      */  
7. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
8. for (HandlerMapping hm : this.handlerMappings) {  
9. if (logger.isTraceEnabled()) {  
10.                 logger.trace(  
11. "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");  
12.             }  
13.             HandlerExecutionChain handler = hm.getHandler(request);  
14. if (handler != null) {  
15. return handler;  
16.             }  
17.         }  
18. return null;  
19.     }

 

最后会调用到父类AbstractHandlerMapping中的getHandler,返回一个HandlerChain(责任链模式)



    1. /**
    2.      * Look up a handler for the given request, falling back to the default
    3.      * handler if no specific one is found.
    4.      * @param request current HTTP request
    5.      * @return the corresponding handler instance, or the default handler
    6.      * @see #getHandlerInternal
    7.      */  
    8. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
    9.         Object handler = getHandlerInternal(request);  
    10. if (handler == null) {  
    11.             handler = getDefaultHandler();  
    12.         }  
    13. if (handler == null) {  
    14. return null;  
    15.         }  
    16. // Bean name or resolved handler?  
    17. if (handler instanceof String) {  
    18.             String handlerName = (String) handler;  
    19.             handler = getApplicationContext().getBean(handlerName);  
    20.         }  
    21. return getHandlerExecutionChain(handler, request);  
    22.     }


     

    HandlerChain中包含了一系列封装Controller的HandlerAdapte

    在接到http请求之后,在HandlerChain中就能找到自己所要执行的控制器。

    其他细节在此打住。