美文网首页日常开发
spring源码之refresh第二篇

spring源码之refresh第二篇

作者: 程序员田同学 | 来源:发表于2022-01-10 11:56 被阅读0次

    大家好,我是程序员田同学

    上篇文章对spring核心启动方法refresh做了整体的解读,但是只是泛泛而谈,接下来会出一系统文章对每个方法的源码进行深刻解读。

    第一篇文章见 spring源码之方法概览

    首先,第一个方法是prepareRefresh()方法,这个方法做的事很简单,也不是本文的重点。该方法记录容器的启动时间,初始化监听容器。

    <pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n5" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background: rgb(51, 51, 51); position: relative !important; padding: 10px 10px 10px 30px; width: inherit; color: rgb(184, 191, 198); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">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<>();
    }
    </pre>

    读者大致搂一眼即可,对这个方法整体就能很快把握。

    接下来才是今天的重头戏——obtainFreshBeanFactory()方法,是refresh()方法中的第二个方法,也是整个refresh()方法中核心方法之一。

    该方法主要的作用是,这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。(Bean 并没有完成初始化)

    image-20220110103559050

    点进去obtainFreshBeanFactory()方法我们一探究竟。

    <pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n12" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background: rgb(51, 51, 51); position: relative !important; padding: 10px 10px 10px 30px; width: inherit; color: rgb(184, 191, 198); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
    refreshBeanFactory();

    // 返回刚刚创建的 BeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
    logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
    }</pre>

    refreshBeanFactory()应该是这个方法的重头戏,我们再深入进去。

    <pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n15" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background: rgb(51, 51, 51); position: relative !important; padding: 10px 10px 10px 30px; width: inherit; color: rgb(184, 191, 198); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">@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);
    }
    }</pre>

    简单提一句,DefaultListableBeanFactory为什么是最牛的BeanFactory看下这个继承图大概就明了。

    image-20220110105719840

    <pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n18" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background: rgb(51, 51, 51); position: relative !important; padding: 10px 10px 10px 30px; width: inherit; color: rgb(184, 191, 198); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"> // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
    customizeBeanFactory(beanFactory);</pre>

    image-20220110110304120

    这个方式只是一个设置,设置是否允许循环依赖,至于什么是循环依赖呢?也就是 A-B-C之间他们相互依赖,spring有一套自己的机制去处理循环依赖,以后文章为进行分析,这一步仅仅是配置是否允许循环依赖,读者清楚就可以了。

    <pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n21" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background: rgb(51, 51, 51); position: relative !important; padding: 10px 10px 10px 30px; width: inherit; color: rgb(184, 191, 198); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"> // 这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中
    loadBeanDefinitions(beanFactory);</pre>

    经过上面一系列的步骤,一个beandefintion就形成,beandefintion就是我们常说的bean,也就是一个对象的加强版。

    接下来就需要把这个bean加入到beanfactory中了,这一步交给loadBeanDefinitions()方法去执行。

    image-20220110111314794

    spring方法命名确实精妙,只看看方法名大概也知道每个方法干了什么!

    创建一个beanDefinitionReader(bean阅读器)去读取xml中的bean,虽然xml很少用了,但是用它来举例还是很经典的。

    真正干活的是loadBeanDefinitions(beanDefinitionReader),往下走很漫长漫长,把我们xml中的bean解析成BeanDefinition,并调用registerBeanDefinition()方法把它注册到注册中心,发送注册事件。

    总结一下,到这里已经初始化了 Bean 容器,<bean /> 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到注册中心,并且发送了注册事件。

    到此obtainFreshBeanFactory() 方法也就正式结束了。

    spring的调用过程链路非常非常的长,一步步点进去没一会你就迷了,田同学认为比较好的一个办法就是,先站在方法体外看这个方法干了什么,然后逐步拆分进入到每一个方法中。

    站在refresh()外看这两个方法,prepareRefresh()准备一下刷新要做的事,obtainFreshBeanFactory()注册好bean并加入到beanfactory中。

    好啦,今天的spring源码分析就到这里了。

    相关文章

      网友评论

        本文标题:spring源码之refresh第二篇

        本文链接:https://www.haomeiwen.com/subject/tebiqrtx.html