共计 3783 个字符,预计需要花费 10 分钟才能阅读完成。
大家好,我是程序员田同学
上篇文章对 spring 外围启动办法 refresh 做了整体的解读,然而只是泛泛而谈,接下来会出一零碎文章对每个办法的源码进行粗浅解读。
第一篇文章见 spring 源码之办法概览
首先,第一个办法是 prepareRefresh() 办法,这个办法做的事很简略,也不是本文的重点。该办法记录容器的启动工夫,初始化监听容器。
protected void prepareRefresh() {
// Switch to active
// 纪录启动工夫
this.startupDate = System.currentTimeMillis();
System.out.println("spring 启动工夫为 --------------------" + this.startupDate);
this.closed.set(false);
System.out.println("spring 标记为未敞开 --------------------" + this.closed);
this.active.set(true);
System.out.println("spring 以后激活状态 --------------------" + this.active);
if (logger.isDebugEnabled()) {if (logger.isTraceEnabled()) {logger.trace("Refreshing" + this);
} else {logger.debug("Refreshing" + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
// 空办法
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 校验 xml 配置文件
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
// 初始化 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<>();}
读者大抵搂一眼即可,对这个办法整体就能很快把握。
接下来才是明天的重头戏——obtainFreshBeanFactory() 办法,是 refresh() 办法中的第二个办法,也是整个 refresh() 办法中外围办法之一。
该办法次要的作用是,这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。(Bean 并没有实现初始化)
点进去 obtainFreshBeanFactory() 办法咱们一探到底。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 敞开旧的 BeanFactory ( 如果有),创立新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
refreshBeanFactory();
// 返回刚刚创立的 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {logger.debug("Bean factory for" + getDisplayName() + ":" + beanFactory);
}
return beanFactory;
}
refreshBeanFactory() 应该是这个办法的重头戏,咱们再深刻进去。
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果 ApplicationContext 中曾经加载过 BeanFactory 了,销毁所有 Bean,敞开 BeanFactory
// 留神,利用中 BeanFactory 原本就是能够多个的,这里可不是说利用全局是否有 BeanFactory,而是以后 ApplicationContext 是否有 BeanFactory
if (hasBeanFactory()) {destroyBeans();
closeBeanFactory();}
try {
// 初始化一个 DefaultListableBeanFactory,为什么应用这个 BeanFactory?因为这是最牛的 BeanFactory。DefaultListableBeanFactory beanFactory = createBeanFactory();
// 用于 BeanFactory 的序列化
beanFactory.setSerializationId(getId());
// 设置 BeanFactory 的两个配置属性:是否容许 Bean 笼罩、是否容许循环援用
customizeBeanFactory(beanFactory);
// 加载 Bean 到 BeanFactory 中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}
}
catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for" + getDisplayName(), ex);
}
}
简略提一句,DefaultListableBeanFactory 为什么是最牛的 BeanFactory 看下这个继承图大略就明了。
// 设置 BeanFactory 的两个配置属性:是否容许 Bean 笼罩、是否容许循环援用
customizeBeanFactory(beanFactory);
这个形式只是一个设置,设置是否容许循环依赖,至于什么是循环依赖呢?也就是 A-B- C 之间他们相互依赖,spring 有一套本人的机制去解决循环依赖,当前文章为进行剖析,这一步仅仅是配置是否容许循环依赖,读者分明就能够了。
// 这个办法将依据配置,加载各个 Bean,而后放到 BeanFactory 中
loadBeanDefinitions(beanFactory);
通过下面一系列的步骤,一个 beandefintion 就造成,beandefintion 就是咱们常说的 bean,也就是一个对象的加强版。
接下来就须要把这个 bean 退出到 beanfactory 中了,这一步交给 loadBeanDefinitions() 办法去执行。
spring 办法命名的确精妙,只看看办法名大略也晓得每个办法干了什么!
创立一个 beanDefinitionReader(bean 阅读器)去读取 xml 中的 bean, 尽管 xml 很少用了,然而用它来举例还是很经典的。
真正干活的是 loadBeanDefinitions(beanDefinitionReader),往下走很漫长漫长,把咱们 xml 中的 bean 解析成 BeanDefinition,并调用 registerBeanDefinition() 办法把它注册到注册核心,发送注册事件。
总结一下,到这里曾经初始化了 Bean 容器,<bean />
配置也相应的转换为了一个个 BeanDefinition,而后注册了各个 BeanDefinition 到注册核心,并且发送了注册事件。
到此 obtainFreshBeanFactory() 办法也就正式完结了。
spring 的调用过程链路十分十分的长,一步步点进去没一会你就迷了,田同学认为比拟好的一个方法就是,先站在办法体外看这个办法干了什么,而后逐渐拆分进入到每一个办法中。
站在 refresh() 外看这两个办法,prepareRefresh() 筹备一下刷新要做的事,obtainFreshBeanFactory() 注册好 bean 并退出到 beanfactory 中。
好啦,明天的 spring 源码剖析就到这里了。