• Spring 源码(2)Spring IOC 容器 前戏准备工作


    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的创建过程。

  • 相关阅读:
    ZDOCK linux 下载(无需安装)、配置、使用
    囚徒逃生问题优化策略
    C语言复习笔记7----二维数组
    蓝牙mesh基础(基本概念)
    vue项目中 jsconfig.json是什么
    JavaScript运算符(运算符(算数运算符,递增和递减运算符,比较运算符,逻辑运算符,赋值运算符)、运算符优先级)
    如何全面提升架构设计的质量
    为什么需要对jvm进行优化,jvm运行参数之标准参数
    Ceph常用命令总结
    基于Java毕业设计在线商城系统源码+系统+mysql+lw文档+部署软件
  • 原文地址:https://www.cnblogs.com/redwinter/p/16151489.html