zoukankan      html  css  js  c++  java
  • 捋一捋Spring Web的源码思路

    Servlet前提

    1. Java规定了Servlet Container为每一个web app创建一个Servlet Context;而Servlet Context中又包含了诸多Servlet -- 其信息由ServletConfig对象持有,存储于Servlet Context的attribute中。
    2. Java提供了ServletContainerInitializer,用于发出通知:某个web应用已经处于启动阶段。--其实顾名思义,就是Servlet Container初始化时会调用这个接口的实现方法 onStartup。
    3. Java提供了五个Listener类 (ServletContextListener、ServletContextAttributeListener、ServletRequestListener、ServletRequestAttributeListener、HttpSessionListener、HttpSessionAttributeListener)来监听Servlet相关的行为。

    Spring前提

    1. Spring Web,其实是创建了WebApplicationContext -- AnnotationConfigWebApplicationContext、XmlWebApplicationContext等。这是Root Application Context。
    2. Spring Web MVC,其实创建了DispatcherServlet,以及一个ServletApplicationContext。

    务必注意,二者是不同的!简单的说,如果是注解驱动的,那Root Application Context对应的是除了@Controller之外的所有bean;而ServletApplicationContext 则只对应@Controller的bean。

    如果不加以区分,可能会导致问题出现。(请搜索 父子容器)

    开始

    其实,明白了上述前提,就很好理解Spring MVC项目的流程了。(说明:这里是以Java-config形式说明的,但对于xml形式来说理论是一样的)

    先来说说Java-config形式的Spring MVC项目都需要哪些配置:

    1、Root Config (包含除了视图层之外的所有配置,可拆分出DataSourceConfig等)

    @Configuration
    @ComponentScan( basePackages = "win.larryzeal.spring",
                    excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) )
    public class AppConfig {
        // ...
    }

    2、MvcConfig

    @Configuration
    @ComponentScan( basePackages = "win.larryzeal.spring",
                    includeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) )
    @EnableWebMvc
    public class MvcConfig {
        // ...
    }

    3、WebAppInitializer(还可注册filter等,等价于web.xml)

    public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        protected Class<?>[] getRootConfigClasses(){
            return new Class[]{AppConfig.class};
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses(){
            return new Class[]{MvcConfig.class};
        }
    
        @Override
        protected String[] getServletMappings(){
            return new String[]{"/"};
        }
    
    }

    其实1和2都很好理解,3在使用上也好理解,但3封装了好几层。如果你点开AbstractAnnotationConfigDispatcherServletInitializer ,一直向上回溯,会发现最后的接口是 WebApplicationInitializer。

    WebApplicationInitializer 这个接口是Spring提供的,它的javadoc说的很明白,它会被 SpringServletContainerInitializer 自动调用。

    而 SpringServletContainerInitializer 则是Spring对 ServletContainerInitializer的实现! -- 对应Servlet前提2

    所以,实际的逻辑是这样的:

    ① Servlet Container启动,调用ServletContainerInitializer的实现(这里就是SpringServletContainerInitializer ) ;

    ② SpringServletContainerInitializer 调用所有的 WebApplicationInitializer 实现 (这里就是我们提供的WebAppInitializer );

    ③ WebAppInitializer 设置了RootConfigClasses和ServletConfigClasses,以及DispatcherServlet的映射路径!

    这里漏掉了Servlet前提3中所说的ServletContextListener,其实Spring也提供了它的实现类:ContextLoaderListener,在Servlet Container为web app创建Servlet Context时,自动创建Root WebApplicationContext。

    鉴于这是一个Listener,我们需要将其注册到Servlet Container中才行,上面③已经替我们做了(见AbstractContextLoaderInitializer#registerContextLoaderListener)! -- 如果使用web.xml,实际上是需要手动注册一下的:

    <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>

    懒得画图了,就这么着吧。

    之前还有一篇,可以看看:

    Spring 4 官方文档学习(十一)Web MVC 框架之编码式Servlet容器初始化

  • 相关阅读:
    前端资源分享
    Java的wait(), notify()和notifyAll()使用心得(转)
    Java 理论与实践: 处理 InterruptedException(转)
    关于线程中断的总结
    Python入门(good)
    看着自己有什么样的资源,利用好这些资源就好了。不要看着别人的资源流口水(转)
    android手机SD卡中的android_secure目录
    Android中ExpandableListView控件基本使用
    华为的面试经历
    Flex强制类型转换错误
  • 原文地址:https://www.cnblogs.com/larryzeal/p/7430148.html
Copyright © 2011-2022 走看看