3

Spring 源码 (2)Spring IOC 容器 前戏准备工作 - 玲丶蹊

 2 years ago
source link: https://www.cnblogs.com/redwinter/p/16151489.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Spring 最重要的方法refresh方法

根据上一篇文章 https://www.cnblogs.com/redwinter/p/16141285.html Spring Bean IOC 的创建流程继续解读Spring源码,本篇文章解读Spring 源码最重要的方法refresh方法。

这个方法位于:AbstractApplicationContext#refresh,这个方法中总共有15个方法,Spring源码的精髓就是这15个方法中。

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 准备工作,加载环境变量等操作
			// 1、设置容器启动时间
			// 2、设置停止状态为false
			// 3、设置活跃状态为true
			// 4、获取Environment对象,并设置属性值
			// 5、设置监听器和事件的集合,模式为空的集合
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 告诉子类刷新内部 bean 工厂, 获取刷新bean的工厂: DefaultListableBeanFactory
			// 并且加载BeanDefinition
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 准备BeanFactory 设置一些属性
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
                 // 允许子类进行扩展BeanFactoryPostProcessor
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 实例化并执行BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 实例化并注册BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				// 国际化设置
				initMessageSource();

				// Initialize event multicaster for this context.
				// 实例化事件多播器
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 初始化特定上下文子类中的其他特殊bean,web容器
				onRefresh();

				// Check for listener beans and register them.
				// 检查listener bean 并注册它们
				// 注册监听器
				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.
				// 销毁Bean
				destroyBeans();

				// Reset 'active' flag.
				// 重置 active 标志
				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();
			}
		}
	}

前戏准备 prepareRefresh 方法

Spring的前戏准备大概就是做了以下几件事:

  • 设置容器的启动时间
  • 设置容器的停止状态为false
  • 设置容器的激活状态为true
  • 获取环境信息并验证必要的属性
  • 准备监听器和事件的容器
protected void prepareRefresh() {
		// Switch to active.
		// 设置启动时间 设置标识位
		this.startupDate = System.currentTimeMillis();
		// 设置容器停止标识为false
		this.closed.set(false);
		// 设置容器激活标识为true
		this.active.set(true);
		// Initialize any placeholder property sources in the context environment.
		// 初始化上下文环境中的任何占位符属性源
		// 留给子类进行扩展,比如添加必须的属性值验证
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		// 获取环境对象,并验证需要的属性
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		// 准备应用监听器和实践的容器初始化
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			// 如果不为空,那么就清空掉,并设置新的早期的监听器进去
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}
		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

这里有个问题就是他的环境信息是何时设置进去的呢?

实际上是在容器启动时调用了父类构造函数时设置进去的,Environment他是一个接口,他有个重要的实现类叫StandardEnvironment ,在Spring启动的时候就会使用这个类进行环境信息的加载,最终他会调用到System#getPropertiesSystem#getenv方法,然后将加载到属性放在Map中进行保存。

大概的流程如下:

标记的类就是Environment环境信息的加载过程调用的类,最终会调用到System#getPropertiesSystem#getenv方法,然后完成环境信息的加载,主要加载的信息就是系统的环境变量,比如在Windows中配置的环境变量或者启动类中使用-D参数配置的启动参数都会进行加载到StandardEnvironment 这个类中,类似于使用-Dxxx.name=123这种参数会加载到systemProperties中,配置的windows环境变量会加载systemEnvironment中。

这个就是Spring IOC 创建的第一个方法的前戏准备工作,接下来解读默认的BeanFactory实现类DefaultListableBeanFactory的创建过程。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK