文章目录
  1. 1. 一.总体初始化流程
  2. 2. 二.详细解析
    1. 2.1. 1.Spring-ContextLoaderListener
    2. 2.2. 2.SpringMVC-DispatcherServlet
    3. 2.3. 3.Spring-RequestContextListener
    4. 2.4. 4.其它的一些类
  3. 3. 三. 参考文献

一.总体初始化流程

web.xml加载顺序,context-param -> listener -> filter -> servlet;

  1. 启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取两个结点;

  2. 紧接着,容器创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文;

  3. 容器将转换为键值对,并交给servletContext;

  4. 容器创建中的类实例,创建监听器。(如spring的ContextLoadListener、RequestContextListener、Log4jConfigListener等)(ContextLoadListener实例化Ioc容器,根据条件决定是否此时实例化bean,如lazy-init,scope等参数);

  5. 构建filter链(如CharacterEncodingFilter、OpenSessionInViewFilter、struts2的StrutsPrepareFilter、StrutsExecuteFilter等);

注意:servlet是单实例多线程;spring bean默认也是单实例的,不过可以通过scope参数来设置为别的;struts2中action是多例的。另外,本文基于spring3.2.2源码来分析的。

二.详细解析

servlet、listener、filter的关键方法

Servlet
-init(ServletConfig config)
-service(ServletRequest req, ServletResponse res)
//service再根据请求类型调用doGet、doPost等方法
-destroy()

Listener
ServletContextListener
-contextInitialized ( ServletContextEvent sce )
-contextDestroyed ( ServletContextEvent sce )
ServletRequestListener
-requestInitialized(ServletRequestEvent requestEvent)
-requestDestroyed(ServletRequestEvent requestEvent)

Filter
-init(FilterConfig filterConfig)
-destroy()
-doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

1.Spring-ContextLoaderListener

ContextLoaderListener作用就是启动Web容器时,自动装配spring的配置文件的配置信息;
ContextLoaderServlet:与ContextLoaderListener功能一样;

ContextLoaderListener它继承了javax.servlet.ServletContextListener接口。ServletContextListener是J2EE Servlet API中的一个标准接口,它能够监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件由ServletContextListener来处理。

Ioc容器实例化流程如图所示:
ContextLoaderListener初始化调用流程
实例化Spring IoC容器的过程中,最主要的两个方法是createWebApplicationContextconfigureAndRefreshWebApplicationContext方法。

createWebApplicationContext方法用于返回XmlWebApplicationContext实例,即Web环境下的Spring IoC容器。

configureAndRefreshWebApplicationContext用于配置XmlWebApplicationContext,读取web.xml中通过contextConfigLocation标签指定的XML文件,实例化XML文件中配置的bean,并在上一步中实例化的容器中进行注册。

完成以上两步的操作后,Spring MVC会将XmlWebApplicationContext实例以属性的方式注册到ServletContext中。此Spring 容器是ROOT上下文,供所有的Spring MVC Servlcet使用。
核心的初始化逻辑都在AbstractApplicationContext的refresh()方法里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public void refresh(){
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
// 注册实现了BeanPostProcessor接口的bean
postProcessBeanFactory(beanFactory);

// 初始化和执行BeanFactoryPostProcessor beans
invokeBeanFactoryPostProcessors(beanFactory);

// 初始化和执行BeanPostProcessor beans
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// 实例化non-lazy-init的单例bean.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

obtainFreshBeanFactory()方法会刷新所有BeanFactory子容器,在此会加载、解析Bean的定义。
finishBeanFactoryInitialization()方法用来实例化bean

bean实例化时机:
若是单例、lazy-init=false且不是抽象类,则实例化,否则等到执行时才实例化;实例化中若有依赖别的bean,需要先实例化依赖的bean。
具体代码逻辑在DefaultListableBeanFactorypreInstantiateSingletons()AbstractBeanFactorydoGetBean(),可以参考Spring 框架的设计理念与设计模式分析

ApplicationContext vs BeanFactory
ApplicationContext的类继承关系如图所示:
ApplicationContext类继承关系
ApplicationContext 由BeanFactory 派生而来,提供了更多面向实际应用的功能。几乎所有的应用场合我们都直接使用ApplicationContext 而非底层的BeanFactory。在BeanFactory 中,很多功能需要以编程的方式实现,而在ApplicationContext中则可以通过配置的方式实现。

ApplicationContext的主要实现类是ClassPathXmlApplicationContextFileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。

WebApplicationContext 是专门为Web 应用准备的,WebApplicationContext 扩展了ApplicationContext。
Spring 分别提供了用于启动WebApplicationContext 的Servlet 和Web 容器监听器:

org.springframework.web.context.ContextLoaderServlet;
org.springframework.web.context.ContextLoaderListener;

两者的内部都实现了启动WebApplicationContext 实例的逻辑,我们只要根据Web 容器的具体情况选择两者之一,并在web.xml 中完成配置就可以了。

2.SpringMVC-DispatcherServlet

DispatcherServlet配置在web.xml中,是springmvc的入口,它的继承关系图如下图所示:
DispatcherServlet类继承图

  1. HttpServletBean继承HttpServlet,因此在Web容器启动时将调用它的init方法,该初始化方法的主要作用:
    a. 将Servlet初始化参数(init-param)设置到该组件上(如contextAttribute、contextClass、namespace、contextConfigLocation),通过BeanWrapper简化设值过程,方便后续使用;
    b. 提供给子类初始化扩展点,initServletBean(),该方法由FrameworkServlet覆盖。
  2. FrameworkServlet继承HttpServletBean,通过initServletBean()进行Web上下文初始化,该方法主要覆盖一下两件事情:
    a. 初始化web上下文;
    b. 提供给子类初始化扩展点;
  3. DispatcherServlet继承FrameworkServlet,并实现了onRefresh()方法提供一些前端控制器相关的配置:
1
2
3
4
5
6
public class DispatcherServlet extends FrameworkServlet {
//实现子类的onRefresh()方法,该方法委托为initStrategies()方法。
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}

//初始化默认的Spring Web MVC框架使用的策略(如HandlerMapping)

1
2
3
4
5
6
7
8
9
10
11
12
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}

从如上代码可以看出,DispatcherServlet启动时会进行我们需要的Web层Bean的配置,如HandlerMapping、HandlerAdapter等,而且如果我们没有配置,还会给我们提供默认的配置。

从如上代码我们可以看出,整个DispatcherServlet初始化的过程和做了些什么事情,具体主要做了如下两件事情:

  1. 初始化Spring Web MVC使用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文);
  2. 初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。

3.Spring-RequestContextListener

ContextLoaderListener实现ServletContextListener监听器接口,而ServletContextListener只负责监听Web容器的启动和关闭的事件。RequestContextListener实现ServletRequestListener监听器接口,该监听器监听HTTP请求事件,Web服务器接收的每次请求都会通知该监听器。

4.其它的一些类

1)CharacterEncodingFilter:字符编码转换filter,这个filter一定要注意顺序,要放在其它filter前面,要不然可能不起作用;

2) OpenSessionInViewFilter:主要功能是用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。跟延迟加载相关。

3) Struts2的入口:StrutsPrepareFilter、StrutsExecuteFilter、StrutsListener

三. 参考文献

  1. web.xml加载顺序
  2. Spring 框架的设计理念与设计模式分析
  3. Servlet 工作原理解析
  4. 第三章 DispatcherServlet详解 ——跟开涛学SpringMVC
  5. <深入分析JAVA web技术内幕-许令波>
  6. spring docs
文章目录
  1. 1. 一.总体初始化流程
  2. 2. 二.详细解析
    1. 2.1. 1.Spring-ContextLoaderListener
    2. 2.2. 2.SpringMVC-DispatcherServlet
    3. 2.3. 3.Spring-RequestContextListener
    4. 2.4. 4.其它的一些类
  3. 3. 三. 参考文献