`
syhu100200
  • 浏览: 22796 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
文章分类
社区版块
存档分类
最新评论
  • tangzlboy: 很长好,学了这么久的入门书籍,这边才是最好的!
    web入门

Spring中MVC框架的底层实现

 
阅读更多

Spring中MVC框架的底层实现
Written by Tony Jiang @ 20120119
Spring中的MVC
Spring MVC的流程

Spring的Sample这里就不讲了,大家自己上网google
Spring 在Web环境下的启动
                按照javaEE标准,Web应用启动web.xml,之后的启动root是ServletContextListener。
                (问题: ContextListener如何启动? 随着web容器启动而启动?是单线程的?线程安全的?)
ContextListener是随着Tomcat的启动而启动,并且只启动这一次,为整个WebContext的启动做准备。
                Spring在Web环境下启动的监听器是:
[java] view plaincopyprint?
public class ContextLoaderListener extends ContextLoader implements ServletContextListener { 
/**
     * Initialize the root web application context.
     */ 
    public void contextInitialized(ServletContextEvent event) { 
        this.contextLoader = createContextLoader(); 
        if (this.contextLoader == null) { 
            this.contextLoader = this; 
        } 
        this.contextLoader.initWebApplicationContext(event.getServletContext()); 
    } 

其中WebApplication的上下文在ContextLoader中初期化
[java] view plaincopyprint?
/**
     * Initialize Spring's web application context for the given servlet context,
     * using the application context provided at construction time, or creating a new one
     * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
     * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
     * @param servletContext current servlet context
     * @return the new WebApplicationContext
     * @see #ContextLoader(WebApplicationContext)
     * @see #CONTEXT_CLASS_PARAM
     * @see #CONFIG_LOCATION_PARAM
     */ 
    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { 
try { 
            // Store context in local instance variable, to guarantee that 
            // it is available on ServletContext shutdown. 
            if (this.context == null) { 
                this.context = createWebApplicationContext(servletContext); 
            }    

最后的启动委托给XmlWebApplicationContext
这个类中使用了大量的模板设计模式!!
最终的容器启动和我们编程式启动Spring类同
[java] view plaincopyprint?
/**
     * Loads the bean definitions via an XmlBeanDefinitionReader.
     * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
     * @see #initBeanDefinitionReader
     * @see #loadBeanDefinitions
     */ 
    @Override 
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { 
        // Create a new XmlBeanDefinitionReader for the given BeanFactory. 
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 
 
        // Configure the bean definition reader with this context's 
        // resource loading environment. 
        beanDefinitionReader.setEnvironment(this.getEnvironment()); 
        beanDefinitionReader.setResourceLoader(this); 
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); 
 
        // Allow a subclass to provide custom initialization of the reader, 
        // then proceed with actually loading the bean definitions. 
        initBeanDefinitionReader(beanDefinitionReader); 
        loadBeanDefinitions(beanDefinitionReader); 
    } 

入口的DispatchServlet
DispatchServlet的初期化和生成,我认为不是由Spring容器负责的,应该是由Web容器自己管理的。可以参考《How tomcat works》这本书
DispatchServlet的init方法在父类的父类的HttpServletBean中
是一个final方法哦
[java] view plaincopyprint?
public final void init() throws ServletException { 
        if (logger.isDebugEnabled()) { 
            logger.debug("Initializing servlet '" + getServletName() + "'"); 
        } 
 
        // Set bean properties from init parameters. 
        try { 
            PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); 
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); 
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); 
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment)); 
            initBeanWrapper(bw); 
            bw.setPropertyValues(pvs, true); 
        } 
        catch (BeansException ex) { 
            logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); 
            throw ex; 
        } 
 
        // Let subclasses do whatever initialization they like. 
        initServletBean(); 
 
        if (logger.isDebugEnabled()) { 
            logger.debug("Servlet '" + getServletName() + "' configured successfully"); 
        } 
    } 


真正的servlet的初期化在子类中执行,又是模板模式~~~
于是我们在子类的FrameworkServlet中看到
[java] view plaincopyprint?
/**
     * Overridden method of {@link HttpServletBean}, invoked after any bean properties
     * have been set. Creates this servlet's WebApplicationContext.
     */ 
    @Override 
    protected final void initServletBean() throws ServletException { 
        getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); 
        if (this.logger.isInfoEnabled()) { 
            this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started"); 
        } 
        long startTime = System.currentTimeMillis(); 
 
        try { 
            this.webApplicationContext = initWebApplicationContext(); 
            initFrameworkServlet(); 
        } 
        catch (ServletException ex) { 
            this.logger.error("Context initialization failed", ex); 
            throw ex; 
        } 
        catch (RuntimeException ex) { 
            this.logger.error("Context initialization failed", ex); 
            throw ex; 
        } 
 
        if (this.logger.isInfoEnabled()) { 
            long elapsedTime = System.currentTimeMillis() - startTime; 
            this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + 
                    elapsedTime + " ms"); 
        } 
    } 


接下来最后将自己sevlet对应上具体的ServletContext
先回顾一下Servlet的生存周期
Servlet的init方法是在容器的启动中被启动,只执行这一次。
那就意味着,Servlet的所需要的资源,内存空间,instance的预实例化都要在init内完成。
作为Spring Servlet的init,那么相对应ServletName -servlet.xml中所有的定义类都必须在init中被成功初期化。
我们拿一个简单ServletName -servlet.xml来举例
[html] view plaincopyprint?
1 <?xml version="1.0" encoding="UTF-8" ?> 
2 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 
3  
4 <beans> 
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  
11     <bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
12         <property name="mappings"> 
13             <props> 
14                 <prop key="/hello.do">helloController</prop> 
15             </props> 
16         </property> 
17     </bean> 
18  
19     <bean id="helloController" class="com.ideawu.HelloController"> 
20         <!-- 
21         <property name="helloManager" ref="helloManager" /> 
22         --> 
23     </bean> 
24  
25 </beans> 


其中包括viewResolver(采用何种视图模板),HandlerMapping(采用何种http拦截器),Controller(对应每种http请求采用何种控制器)。
所有的这些,都是通过Spring容器本身进行加载的。
DispatchServlet中这些资源的加载是在本身的initStrategies方法内执行(通过父类模板方法的调用)
[java] view plaincopyprint?
/**
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */ 
    protected void initStrategies(ApplicationContext context) { 
        initMultipartResolver(context); 
        initLocaleResolver(context); 
        initThemeResolver(context); 
        initHandlerMappings(context); 
        initHandlerAdapters(context); 
        initHandlerExceptionResolvers(context); 
        initRequestToViewNameTranslator(context); 
        initViewResolvers(context); 
        initFlashMapManager(context); 
    } 


关于HandlerMapping
                handlerMaper是一个单例的(相对于一个JVM而言)的ArrayList
                它的初期化在DispatchServlet中
[java] view plaincopyprint?
/**
     * Initialize the HandlerMappings used by this class.
     * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
     * we default to BeanNameUrlHandlerMapping.
     */ 
    private void initHandlerMappings(ApplicationContext context) { 
        this.handlerMappings = null; 
 
        if (this.detectAllHandlerMappings) { 
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. 
            Map<String, HandlerMapping> matchingBeans = 
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); 
            if (!matchingBeans.isEmpty()) { 
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); 
                // We keep HandlerMappings in sorted order. 
                OrderComparator.sort(this.handlerMappings); 
            } 
        } 
        else { 
            try { 
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); 
                this.handlerMappings = Collections.singletonList(hm); 
            } 
            catch (NoSuchBeanDefinitionException ex) { 
                // Ignore, we'll add a default HandlerMapping later. 
            } 
        } 
 
        // Ensure we have at least one HandlerMapping, by registering 
        // a default HandlerMapping if no other mappings are found. 
        if (this.handlerMappings == null) { 
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); 
            if (logger.isDebugEnabled()) { 
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); 
            } 
        } 
    } 


它的被执行是在DispatchServlet中的doService中
[java] view plaincopyprint?
/**
     * Return the HandlerExecutionChain for this request.
     * <p>Tries all handler mappings in order.
     * @param request current HTTP request
     * @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
     */ 
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 
        for (HandlerMapping hm : this.handlerMappings) { 
            if (logger.isTraceEnabled()) { 
                logger.trace( 
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); 
            } 
            HandlerExecutionChain handler = hm.getHandler(request); 
            if (handler != null) { 
                return handler; 
            } 
        } 
        return null; 
    } 


最后会调用到父类AbstractHandlerMapping中的getHandler,返回一个HandlerChain(责任链模式)
[java] view plaincopyprint?
/**
     * Look up a handler for the given request, falling back to the default
     * handler if no specific one is found.
     * @param request current HTTP request
     * @return the corresponding handler instance, or the default handler
     * @see #getHandlerInternal
     */ 
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 
        Object handler = getHandlerInternal(request); 
        if (handler == null) { 
            handler = getDefaultHandler(); 
        } 
        if (handler == null) { 
            return null; 
        } 
        // Bean name or resolved handler? 
        if (handler instanceof String) { 
            String handlerName = (String) handler; 
            handler = getApplicationContext().getBean(handlerName); 
        } 
        return getHandlerExecutionChain(handler, request); 
    } 

HandlerChain中包含了一系列封装Controller的HandlerAdapte
在接到http请求之后,在HandlerChain中就能找到自己所要执行的控制器。
其他细节在此打住。
分享到:
评论

相关推荐

    ServletJSPSpringMVC初学指南.zip

    Servlet 和JSP 是Java Web 应用开发的底层技术,而Spring MVC 是Spring 框架中用于解决Servlet 和JSP 应用开发的常见和通用问题的一个模块。Spring MVC 是一个广泛应用于GUI 开发的设计模式,是目前业界主流的Web ...

    java练习测试-spring mvc-erp

    没事可以练练手,底层jpa注解实现,spring管理bean,spring mvc框架,是一个不错的练手练习。

    看透springMvc源代码分析与实践.pdf

    系统理解Spring MVC框架,为灵活开发高质量产品打下坚实基础。 深入理解Spring MVC的编程技巧和设计理念,提高综合思考、整体架构的能力。 学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。

    Spring+3.x企业应用开发实战光盘源码(全)

     第6章:我们从Spring AOP的底层实现技术入手,一步步深入到Spring AOP的内核中,分析它的底层结构和具体实现。  第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、...

    图解springMVC执行流程及原理.docx

    使用 Spring 可插入的 MVC架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架。 SpringMVC执行流程概括 SpringMVC框架固然强大,但是其执行流程更是妙不可言。所以我们...

    看透springMvc源代码分析与实践-扫描版本

    系统理解Spring MVC框架,为灵活开发高质量产品打下坚实基础。 深入理解Spring MVC的编程技巧和设计理念,提高综合思考、整体架构的能力。 学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。

    看透SpringMVC源代码分析与实践(扫描版)

     系统理解Spring MVC框架,为灵活开发高质量产品打下坚实基础。  深入理解Spring MVC的编程技巧和设计理念,提高综合思考、整体架构的能力。  学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。

    看透springMvc源代码分析与实践

    在大型网站和复杂系统的开发中,Java具有天然的优势,而在Java的Web框架中Spring MVC以其强大的功能以及简单且灵活的用法受到越来越多开发者的青睐。本书不仅详细地分析Spring MVC的结构及其实现细节,而且讲解网站...

    Spring-Reference_zh_CN(Spring中文参考手册)

    13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 13.4. ...

    Spring中文帮助文档

    13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 ...

    spring-framework-5-0-0-m3-zh_cn

    Spring Framework 是一种轻量级的解决方案,是构建你的企业级应用程序的潜在一站式解决 方案。 尽管如此, Spring 是模块化的,允许你只...它提供了一个全功能的 MVC 框架,并使你能够将 AOP 透明地集成到你的软件中

    入门案例-SpringMVC技术架构图

    Spring MVC以DispatcherServlet为核心,众多组件如HandlerMapping为辅助,为用户封装了请求映射等底层逻辑,让用户可以更专注与业务逻辑的处理。本文会对Spring MVC整体结构做简单介绍。 Spring MVC结构图 Spring ...

    基础的java web项目,完成了应用骨架的搭建,提供了底层框架的支持

    (4)集成的框架有:spring mvc + spring + hibernate + logback + junit,spring mvc、hibernate已经用注解配置方式替代 了传统的xml配置方式。 (5)logback在本项目中已经设置了一个aop切面,对所有的controller请求...

    陈开雄 Spring+3.x企业应用开发实战光盘源码.zip

     第6章:我们从Spring AOP的底层实现技术入手,一步步深入到Spring AOP的内核中,分析它的底层结构和具体实现。  第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、...

    java三大框架

    Struts只是一个MVC框架(Framework),用于快速开发Java Web应用。Struts实现的重点在C(Controller),包括ActionServlet/RequestProcessor和我们定制的 Action,也为V(View)提供了一系列定制标签(Custom Tag)。但...

    手写的minispringmvc

    通过手写一个五脏俱全的minispringmvc。可以快速理解springmvc的底层实现原理。面试加分哦.用maven导入

    Spring 2.0 开发参考手册

    13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 ...

    springmvc web框架 mvc模式

    对于springmvc框架的分析,以及详细的讲解,适合新手,底层技术的实现!

Global site tag (gtag.js) - Google Analytics