栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring启动流程(备用学习)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring启动流程(备用学习)

Spring启动流程

我们在web服务中是怎么启动Spring容器的,我们通常是在web.xml中配置了一个ContextLoaderListener的监听器,然后设置contextConfigLocation,

1、ContextLoaderListener

这个ContextLoaderListener监听器继承了ContextLoader实现了ServletContextListener

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    
    public ContextLoaderListener() {
    	}
    
    public ContextLoaderListener(WebApplicationContext context) {
		super(context);
	}
    
	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}

	
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}
}

所以当web容器启动后就会被监听到,然后调用contextInitialized方法,进而执行initWebApplicationContext方法。然而这个方法是继承于ContextLoader这个父类,一看这个类的名字就知道这就是一个上下文的加载器。

2、ContextLoader

接下来具体看下initWebApplicationContext方法的实现。而且容器的实际初始化工作是从这里开始的。

总的来说,就是干了下面几件事:
1、初始化之前检查当前ServletContext是否已经存在Spring容器;
2、使用无参构造(Java类)或者主要构造(Kotlin类)实例化1个ConfigurableWebApplicationContext实现类,默认是XMLWebApplicationContext;
3、为已经实例化的ConfigurableWebApplicationContext设置父容器,通常为null,除非自定义子类复写loadParentContext。
4、配置并刷新ConfigurableWebApplicationContext(重点);
5、以WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为key存储在当前ServletContext中;
6、将ConfigurableWebApplicationContext存储在当前ContextLoader内部。

这里面最重要的方法是configureAndRefreshWebApplicationContext(cwac, servletContext) ,负责为ConfigurableWebApplicationContext设置一些属性为接下来的refresh做准备

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}

		
		wac.setServletContext(sc);
		
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			
			wac.setConfigLocation(configLocationParam);
		}

		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}

		
		customizeContext(sc, wac);

		
		wac.refresh();
	}

可以看到先是为ConfigurableWebApplicationContext设置了一些属性,然后开始refresh容器
1、设置ConfigurableWebApplicationContext的unique id;
2、调用wac.setServletContext(sc),设置ServletContext为当前ServletContext;
3、获取web.xml中contextConfigLocation配置信息,并调用wac.setConfigLocation(configLocationParam)进行设置(重要)
4、提前初始化PropertySources以便在refresh前执行一些后处理或者初始化工作。
5、自定义一些容器配置,设置了ConfigLocation之后,refresh之前执行
6、上面工作完成后,开始refresh容器(很重要!很重要!很重要!)

属性设置完成,要刷新容器了,我们进入AbstractApplicationContext的refresh() 来一探究竟!

3、 AbstractApplicationContext

首先看下refresh()方法实现,这是Spring容器初始化最核心的方法,前面都只是准备工作,不管以哪种方式启动Spring容器,最终必定会调用这个方法。限于篇幅原因,本篇博客只是大致介绍refresh方法各个流程,让大家先有个印象,具体每个流程的细节将会在后续博客陆续阐述。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			
			prepareRefresh();

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

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				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();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

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

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/843110.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号