参考网站:https://blog.csdn.net/aini201/article/details/77097314

当Web应用启动时,contextInitialized方法会执行载入根上下文(IOC容器):

(1)spring的web项目启动的时候会,启动我们常用的监听类。

      <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/classes/spring-context.xml</param-value>
</context-param>
<!-- Spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

spring容器启动原理,参考资料:https://blog.csdn.net/qq_31854907/article/details/86300901

(2)tomcat在加载web应用时候,会针对每个web.xml的监听器进行创建,看org.apache.catalina.core.StandardContext.listenerStart(),

public boolean listenerStart() {
    if (log.isDebugEnabled())
        log.debug("Configuring application event listeners");


    String listeners[] = findApplicationListeners();
    Object results[] = new Object[listeners.length];
    boolean ok = true;
    for (int i = 0; i < results.length; i++) {
        if (getLogger().isDebugEnabled())
            getLogger().debug(" Configuring event listener class '" + listeners[i] + "'");
        try {
            String listener = listeners[i];
            results[i] = getInstanceManager().newInstance(listener);
        } catch (Throwable t) {
            t = ExceptionUtils.unwrapInvocationTargetException(t);
            ExceptionUtils.handleThrowable(t);
            getLogger().error(sm.getString("standardContext.applicationListener", listeners[i]), t);
            ok = false;
        }
    }
    if (!ok) {
        getLogger().error(sm.getString("standardContext.applicationSkipped"));
        return (false);
    }


    ArrayList<Object> eventListeners = new ArrayList<>();
    ArrayList<Object> lifecycleListeners = new ArrayList<>();
    for (int i = 0; i < results.length; i++) {
        if ((results[i] instanceof ServletContextAttributeListener)
                || (results[i] instanceof ServletRequestAttributeListener)
                || (results[i] instanceof ServletRequestListener)
                || (results[i] instanceof HttpSessionIdListener)
                || (results[i] instanceof HttpSessionAttributeListener)) {
            eventListeners.add(results[i]);
        }
        if ((results[i] instanceof ServletContextListener)
                || (results[i] instanceof HttpSessionListener)) {
            lifecycleListeners.add(results[i]);
        }
    }


    for (Object eventListener : getApplicationEventListeners()) {
        eventListeners.add(eventListener);
    }
    setApplicationEventListeners(eventListeners.toArray());
    
    for (Object lifecycleListener : getApplicationLifecycleListeners()) {
        lifecycleListeners.add(lifecycleListener);
        if (lifecycleListener instanceof ServletContextListener) {
            noPluggabilityListeners.add(lifecycleListener);
        }
    }
    setApplicationLifecycleListeners(lifecycleListeners.toArray());


    if (getLogger().isDebugEnabled())
        getLogger().debug("Sending application start events");


    getServletContext();
    context.setNewServletContextListenerAllowed(false);


    Object instances[] = getApplicationLifecycleListeners();
    if (instances == null || instances.length == 0) {
        return ok;
    }


    ServletContextEvent event = new ServletContextEvent(getServletContext());
    ServletContextEvent tldEvent = null;
    if (noPluggabilityListeners.size() > 0) {
        noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext());
        tldEvent = new ServletContextEvent(noPluggabilityServletContext);
    }
    for (int i = 0; i < instances.length; i++) {
        if (!(instances[i] instanceof ServletContextListener))
            continue;
        ServletContextListener listener = (ServletContextListener) instances[i];
        try {
            fireContainerEvent("beforeContextInitialized", listener);
            if (noPluggabilityListeners.contains(listener)) {
                listener.contextInitialized(tldEvent);
            } else {
                listener.contextInitialized(event); 
            }
            fireContainerEvent("afterContextInitialized", listener);//注册事件
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            fireContainerEvent("afterContextInitialized", listener);
            getLogger().error(sm.getString("standardContext.listenerStart", instances[i].getClass().getName()), t);
            ok = false;
        }
    }
    return (ok);
}

(3)具体的创建wepapplicationcontext的过程如下:

ContextLoaderListener.contextInitialized(ServletContextEvent event) 

 
->ContextLoader.initWebApplicationContext(ServletContext servletContext) 

 启动spring容器


->ContextLoader.createWebApplicationContext(ServletContext sc) - - - - - 如果web.xml里没指定类型,默认是XmlWebAppalication()

 
->ContextLoader.configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc)  - - - - - -  配置和初始化 webApplicationContext的子类是ConfigrableWebApplicationContext

 
->ConfigurableWebApplicationContext.refresh() - - - - -  ConfigurableWebApplicationContext是接口

 
->AbstractApplicationContext.refresh() - - - - - 启动 容器初始化

 
->AbstractApplicationContext.obtainFreshBeanFactory() - - - - -  创建BeanFactory(DefaultListableBeanFactory),以及工厂的初始化

 
->AbstractRefreshableApplicationContext.refreshBeanFactory() - - - - - 在这里创建了BeanFactory(DefaultListableBeanFactory)。然后开始loadBeanDefinitions,这是一个抽象方法,实际的载入是在XmlWebApplicationContext类里。

 
->XmlWebApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) - - - -创建一个XmlBeanDefinitionReader,并启动bean定义信息的载入。

 
->XmlWebApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader) - - - 根据配置文件的locations,因为配置文件是xml的,所以使用的是XmlBeanDefinitionReader 。具体的载入过程是委托给BeanDefinitionReader完成的
 
->AbstractBeanDefinitionReader.loadBeanDefinitionReader - - - 这是一个抽象类,实际的载入是在XmlBeanDefinitionReader中实现的,抽象类是根据bean定义的xml配置文件的路径,生成resource。然后XmlBeanDefinitionReader根据resource开始具体载入BeanDefinition

 
->XmlBeanDefinitionReader.loadBeanDefinitionReader(Resource resource)
 
->XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) - - - 在读取器中,需要得到代表XML文件的resource,这个resource对象封装了对xml文件的IO操作,所以读取器可以在打开IO流后得到XML的文件对象。
 
->XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource) - - - -读取器在这里打开IO流后得到XML的文件Document对象(Document对象是通过XML解析器出来的,下面会再根据Spring Bean的规则再解析出BeanDefinition)。得到对象后就可以按照spring的Bean定义规则来对这个xml的文件档树进行解析了
 
->XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource) - - -这个方法启动对BeanDefinition的解析的详细过程,这个解析会使用到Spring的Bean的配置规则。具体的过程是有BeanDefinitionDocumentReader来完成的。
->BeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
 
->DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext) - - - - -DefaultBeanDefinitionDocumentReader 是BeanDefinitionDocumentReader的实现类,registerBeanDefinitions方法开始按照Spring Bean的规则解析Document对象
 
->DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root) - - -解析过程是由BeanDefinitionParserDelegate对象来完成的。

 
->DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 
->DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
->DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
 - - - - 解析的结果是由BeanDefinitionHolder来持有的,这个BeanDefinitionHolder对象封装了BeanDefinition,beanName,aliases等信息,用它来完成向IOC容器注册。

 
->BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele) 
->BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)
->BeanDefinitionParserDelegate.parseBeanDefinitionElement(
               Element ele, String beanName, BeanDefinition containingBean) - - - 对xml配置文件中的配置的Bean进行详细解析,这里只是读取定义 的<bean>,并载入到BeanDefinition中去,这里不涉及对象的实例化过程,对象的实例化实际上是再依赖注入时完成的。

spring 加载重要过程

SpringApplication.run(Class<?>[] primarySources, String[] args)		--- 开始启动spring应用
	new SpringApplication()											--- 实例化spring应用对象、以及一些相关信息的初始化
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));	--- 通过SPI(spring.factories)机制加载初始化工具
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));				--- 通过SPI(spring.factories)机制加载监听器
	run()															--- 开始spring应用启动过程
		ConfigurableApplicationContext context = null;				定义spring容器的上下文环境,
		context = createApplicationContext();						初始化应用的上下文,并加载基础的注解解释器
			BeanUtils.instantiateClass(Class<T> clazz)				进行上下文环境对象的实例化,及属性的初始化
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);	加载上下文所处的环境配置
		refreshContext(context);									刷新加载上下文内容
			((AbstractApplicationContext) applicationContext).refresh();	更新spring容器上下文的底层信息
				ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();		创建并加载上下文context的bean工厂
				invokeBeanFactoryPostProcessors(beanFactory);			调用bean工厂中的bean的解析器(xml形式的bean解析器,注解annotation形式的解析器),进行bean的加载
					PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); 加载bean
						invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);	通过制定的解析器加载bean
							ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
								processConfigBeanDefinitions(registry);
									List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); 包含着应用中所使用到的bean的信息(名称、指向的对象)
									this.reader.loadBeanDefinitions(configClasses);			加载spring中通过xml或者annotation形式定义的bean,到context的factory中

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐