【深入理解Spring源码】-容器如何初始化?

                                               Spring源码-容器如何初始化?

 

 

初始化Spring如下

 AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
 applicationContext.start();

 

查看源码:

	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

/**
	 * Create a new ClassPathXmlApplicationContext with the given parent,
	 * loading the definitions from the given XML files.
	 * @param configLocations array of resource locations
	 * @param refresh whether to automatically refresh the context,
	 * loading all bean definitions and creating all singletons.
	 * Alternatively, call refresh manually after further configuring the context.
	 * @param parent the parent context
	 * @throws BeansException if context creation failed
	 * @see #refresh()
	 */
  /**
    第一个参数是 spring的配置文件可能是多个
    第二个参数是  是否自动刷新容器,加载所有定义并创建所有单例。否则,在更多其他配置操作后,手动刷新容器
    第三个参数  parent  null
  */
	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
        // 调用父类构造器
		super(parent);
        // 配置文件相关
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

 

主要是通过refresh进行bean的初始化

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
            // 准备刷新的上下文环境
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
            // 初始化BeanFactory,并进行XML文件读取
			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.
                // 子类覆盖方法做额外处理
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
                // 激活各种BeanFactory处理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
                // 注册拦截Bean 创建Bean的处理器,这里只是注册,真正调用的是getBean的时候
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
                // 为上下文初始化Message源, 不同语言的消息体,国际化处理
				initMessageSource();

				// Initialize event multicaster for this context.
                //初始化消息广播器,并放入applicationEventMulticastBean中
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
                //留给子类来初始化其他的bean
				onRefresh();

				// Check for listener beans and register them.
                // 在所有注册的bean中,查找 Listener Bean  注册到广播消息中
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
                // 初始化生效的单实例(非惰性的)
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
                // 完成刷新过程,通知生命周期处理器LifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
				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();
			}
		}
	}

 

总结下ClasspathXmlApplicationContext初始化过程

  1. 初始化前的准备工作,例如对系统属性或者环境变量进行准备验证,在某些情况下项目的使用需要读取某些系统变量,prepareRefresh()这个变量就显得十分必要
  2. 初始化BeanFacory 对xml文件进行读取
  3. 对BeanFactory进行各种功能填充. @Autowried和@Qualifier就是这时填充的
  4.  子类覆盖方法做额外的处理
  5. 激活各种BeanFactory处理器。
  6. 注册拦截bean创建的bean处理器,这里只是注册,真正的调用是在getBean时候。
  7. 为上下文初始化Message源,即对不同语言的消息体进行国际化处理。
  8. 初始化应用消息广播器,并放入“applicationEvent-Multicaster”bean中。
  9. 留给子类来初始化其他的bean。
  10. 在所有注册的bean中查找listener bean,注册到消息广播器中。
  11. 初始化剩下的单实例(非惰性的)。
  12. 完成刷新过程,通知生命周期处理器lifecycleProces-sor刷新过程,同时发出Context RefreshEvent通知别人。

@Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者,否则将抛出异常

@Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者,具体使用方式如下:

 

初始化前的准备工作prepareRefresh()

	protected void prepareRefresh() {
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isInfoEnabled()) {
			logger.info("Refreshing " + this);
		}

		// Initialize any placeholder property sources in the context environment
        //初始化环境变量参数 留给子类覆盖initPropertySources()空的,没有任何逻辑
		initPropertySources();

		// Validate that all properties marked as required are resolvable
		// see ConfigurablePropertyResolver#setRequiredProperties
        // 验证需要的属性文件是否都放入环境中
		getEnvironment().validateRequiredProperties();

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
	}

关注两个函数

(1)initPropertySources正符合Spring的开放式结构设计,给用户最大扩展Spring的能力。用户可以根据自身的需要重写initPropertySources方法,并在方法中进行个性化的属性处理及设置。
(2)validateRequiredProperties则是对属性进行验证,那么如何验证呢?我们举个融合两句代码的小例子来帮助大家理解。

 

加载BeanFactory的obtainFreshBeanFactory()方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

 

 

 

 

 

 

参考资料

wangxiaoming CSDN认证博客专家 架构 Spring Boot Redis
博客是很好的总结和记录工具,如果有问题,来不及回复,关注微信公众号:程序员开发者社区,获取我的联系方式,向我提问,也可以给我发送邮件,联系 1275801617@qq.com
©️2020 CSDN 皮肤主题: Age of Ai 设计师: meimeiellie 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值