Spring启动源码分析笔记

1,Spring搭建的web项目启动首先会加载的webapp/WEB-INF/web.xml文件。其中配置:

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


@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}

该配置仅看名称就知道它是Spring容器启动的核心,上下文加载监听器。
进入该类方法的initWebApplicationContext()方法

//删除一些日志代码以及cache块
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		//检查web.xml文件是否配置多个ContextLoader
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException();
		}
		try {
			if (this.context == null) {
				//创建webIOC容器。查看web.xml文件是否配置了contextClass属性,如有则创建指定的容器,否则采用默认的ContextLoader.properties中的XmlWebApplicationContext容器,通过反射构造创建IOC容器
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
					//此时容器还没有refreshed。设置父容器,设置容器的ID等。
					if (cwac.getParent() == null) {
						//加载web.xml文件是否配置了locatorFactorySelector属性
						//加载web.xml文件是否配置parentContextKey属性
							//如配置了parentContextKey属性,
							//创建BeanFactoryLocator对象 如果locatorFactorySelector属性为空。默认加载classpath*:beanRefContext.xml,
							//根据BeanFactoryLocator.useBeanFactory()获取父容器
						//如为配置parentContextKey则返回null
							
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					//*********最重要的部分在这里。它是容器刷新的关键方法。*********
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
		//在servletContext中添加容器已经初始化标识
		servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
			return this.context;
		}
	
	}

进入configureAndRefreshWebApplicationContext()方法,删除设置ID简单的一些代码

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		//设置容器资源路径,通过web.xml配置contextConfigLocation加载的资源路径
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}
		//创建运行环境,确保servlet属性源,用于以下刷新之前的任何后处理或者初始化操作。
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			//将servletContext资源添加容器环境中
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}
		//1:获取配置文件中所有配置globalInitializerClasses、contextInitializerClasses属性中的ApplicationContextInitializer.class对象
		//2:将所有上述所有的class进行反射构造对象,并添加到集合中并进行排序
		//3:循环依次执行ApplicationContextInitializer.initialize()方法
		customizeContext(sc, wac);
		//刷新容器,加载组件核心方法
		wac.refresh();
	}

进入AbstractApplicationContext.refresh()方法

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			//准备该上下文进行刷新
			/**
			 * 1,记录刷新开始时间,将上下文设置未关闭,已开启状态
			 * 2.在上下文环境中初始化任何占位符属性源,从serveltContext获取配置文件属性
			 * 3.校验所有的properties属性是否可以正常的解析
			 * 4.初始化早起发布应用事件
			 */
			prepareRefresh();
			//通知子类刷新内部工厂
			/**
			 * 1.首先执行refreshBeanFactory()方法,判断是否存在beanfactory 如存在销毁以及关闭
			 * 2.创建DefaultListableBeanFactory对象,并设置序列号ID,设置是否允许重写BeanDefinition,是否允许循环依赖。
			 * 3.加载BeanDefinition,具体执行AbstractRefreshableApplicationContext.loadBeanDefinitions(beanfactory)方法,
			 * 		以XmlWebApplicationContext为例子。
			 * 		1.创建XmlBeanDefinitionReader对象,设置环境、资源加载者、添加解析实体(META-INF/spring.schemas)
			 * 		2.执行XmlWebApplicationContext。initBeanDefinitionReader(beanDefinitionReader)空方法,子类重写,提供了一个扩展功能
			 * 		3.解析配置文件bean元素,并注册为beanDefinition信息,保存在缓存中。
			 */
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			/** 配置工厂上下文标准特征 如上下文的后置处理器
			 *	1:为beanFactory设置classLoader、SPEL表达解析器、添加属性编辑注册器
			 *	2:添加ApplicationContextAwareProcessor后置处理器,
			 */
			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();
			}
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值