1.在web.xml中listener,filter,servlet的执行顺序是:listener>filter>servlet.
ContextLoaderListener#contextInitialized方法最先执行,主要是利用父类ContextLoader初始化spring的WebApplicationContext(上下文),初始化beanFactory(通过scan和读取xml的bean)创建bean。
bean全部执行完了后,开始执行DispatcherServlet,路由请求到具体的bean上。
(整体思路如上,具体实现继续学习。。。)
tomcat启动过程中针对每个web.xml创建ServletContextEvent对象event(通知Web应用的servlet上下文更改的事件类,提供了获取ServletContext的方法),将该对象传入listener.contextInitialized(event),相当于:ContextLoaderListener#contextInitialized(event)。
在contextInitialized方法中,调用了初始化spring应用上下文的initWebApplicationContext(event)方法,在initWebApplicationContext方法中,获取上下文ServletContext的自定义属性WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE是否有值,如果有值表示该应用已经启动过了或者存在了两个web.xml,抛出异常。如果为空,执行初始化WebApplicationContext对象的操作。判断WebApplicationContext对象是否存在(在修改代码热启动的情况下该对象可能是存在的),如果不存在,就进行创建操作,执行ConfigurableWebApplicationContext的refresh方法(方法体内执行了很多准备工作,详情见AbstractApplicationContex.refresh()),接着判断当前初始化spring的加载器是WebAppClassLoader还是其他加载器(区别见后文注释1),如果是相同的,就把WebApplicationContext放在ContextLoader成员变量volatile WebApplicationContext currentContext下,如果不同就放在map下。(不详不实部分,多读几遍明白了运用场景再修改)
注释1:
webapp的加载类是:WebAppClassLoader
tomcat中common文件里面jar加载类是:CommonClassloader
tomcat中share文件里面jar加载类是:ShareClassloader
tomcat中Catalina的加载类是:CatalinaClassloader
CommonClassLoader 能加载的类都可以被 CatalinaClassLoader 和 SharedClassLoader 使用,而 CatalinaClassLoader 和 SharedClassLoader 自己能加载的类则与对方相互隔离。WebAppClassLoader 可以使用 SharedClassLoader 加载到的类,但各个 WebAppClassLoader 实例之间相互隔离。
当同一个tomcat中运行多个war的时候,存在将spring的jar放在common文件夹或者share文件夹下的情况,这时候加载spring的classLoader就是CommonClassloader或者ShareClassloader,而不是WebAppClassLoader,将应用上下文的对象放到root上下文的map中,利用键值对来分别存放应用的上下文。