栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring-IOC-Bean的声明周期(销毁阶段)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring-IOC-Bean的声明周期(销毁阶段)

主要包含:
1.bean销毁前IOC容器的处理
2.bean销毁阶段的回调

ApplicationContext#stop
public void stop() {
    getLifecycleProcessor().stop();
    publishEvent(new ContextStoppedEvent(this));
}

LifecycleProcessor处理器的stop方法也是先给所有Lifecycle bean分组,排序,依次调用stop方法。

ApplicationContext#close
public void close() {
    synchronized (this.startupShutdownMonitor) {
        doClose();
        if (this.shutdownHook != null) {
            try {
                Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
            }
            // catch ......
        }
    }
}

核心方法doClose()。

doClose
protected void doClose() {
    // Check whether an actual close attempt is necessary...
    if (this.active.get() && this.closed.compareAndSet(false, true)) {
        // logger ......
        LiveBeansView.unregisterApplicationContext(this);
        try {
            // Publish shutdown event.
            publishEvent(new ContextClosedEvent(this));
        } // catch ......
        // ......

核心逻辑:广播ContextClosedEvent 事件。

LifecycleProcessor#onClose
 // ......
        // Stop all Lifecycle beans, to avoid delays during individual destruction.
        if (this.lifecycleProcessor != null) {
            try {
                this.lifecycleProcessor.onClose();
            } // catch ......
        }
        // ......

public void onClose() {
    stopBeans();
    this.running = false;
}
destroyBeans - 销毁bean
 // ......
        // Destroy all cached singletons in the context's BeanFactory.
        destroyBeans();
        // ......
        
protected void destroyBeans() {
    getBeanFactory().destroySingletons();
}

获取到 ApplicationContext 内部的 BeanFactory ,让它去销毁所有的单实例 bean 。

DefaultListableBeanFactory#destroySingletons
//DefaultListableBeanFactory#destroySingletons
public void destroySingletons() {
    super.destroySingletons();
    // 清空单实例bean的名称
    updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
    clearByTypeCache();
}

private final Map, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
private final Map, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
private void clearByTypeCache() {
    this.allBeanNamesByType.clear();
    this.singletonBeanNamesByType.clear();
}

1.首先调用父类DefaultSingletonBeanRegistry 的destroySingletons 方法。
2.随后会清空所有的单实例 bean 的名称,以及 “类型到 name ” 的映射。( allBeanNamesByType 中保存了 bean 的类型包含的所有 bean ,如 Person 类型的 bean 在 IOC 容器中包含 master 和 admin )

DefaultSingletonBeanRegistry#destroySingletons
//DefaultSingletonBeanRegistry#destroySingletons
public void destroySingletons() {
    // logger ......
    synchronized (this.singletonObjects) {
        this.singletonsCurrentlyInDestruction = true;
    }

    String[] disposableBeanNames;
    synchronized (this.disposableBeans) {
        // set -> array
        disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
    }
    // 销毁所有单实例bean
    for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
        destroySingleton(disposableBeanNames[i]);
    }

    // 清空一切缓存
    this.containedBeanMap.clear();
    this.dependentBeanMap.clear();
    this.dependenciesForBeanMap.clear();

    clearSingletonCache();
}

核心:逐个销毁单实例bean。

destroySingleton

单个bean的销毁流程:

public void destroySingleton(String beanName) {
    super.destroySingleton(beanName);
    removeManualSingletonName(beanName);
    clearByTypeCache();
}

还是调用DefaultSingletonBeanRegistry 中的destroySingleton:

//DefaultSingletonBeanRegistry#destroySingleton
public void destroySingleton(String beanName) {
    // Remove a registered singleton of the given name, if any.
    // 此处会清理掉BeanFactory中设计的用于处理bean循环依赖的三级缓存
    removeSingleton(beanName);

    // Destroy the corresponding DisposableBean instance.
    DisposableBean disposableBean;
    synchronized (this.disposableBeans) {
        disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
    }
    destroyBean(beanName, disposableBean);
}

核心:
1.清空BeanFactory中用于处理循环依赖的缓存。
2.回调bean的销毁动作。

destroyBean
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
    Set dependencies;
    synchronized (this.dependentBeanMap) {
        dependencies = this.dependentBeanMap.remove(beanName);
    }
    if (dependencies != null) {
        // logger ......
        for (String dependentBeanName : dependencies) {
            destroySingleton(dependentBeanName);
        }
    }
    // ......

在销毁一个 bean 时,如果它有依赖其它的 bean ,则首要目标不是销毁自己,而是先销毁那些依赖的 bean ,所以这里会有递归调用上面 destroySingleton 方法的动作。

自定义bean销毁方法的回调
   // ......
    // Actually destroy the bean now...
    if (bean != null) {
        try {
            bean.destroy();
        }
        // catch ......
    }
    // ......
public void destroy() {
    if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
        // 回调DestructionAwareBeanPostProcessor
        // 此处会有执行@PreDestroy注解标注的销毁方法
        for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
            processor.postProcessBeforeDestruction(this.bean, this.beanName);
        }
    }

    if (this.invokeDisposableBean) {
        // logger ......
        try {
            // ......
            else {
                // 回调DisposableBean接口的destroy方法
                ((DisposableBean) this.bean).destroy();
            }
        }
        // catch ......
    }

    // 回调自定义的destroy-method方法
    if (this.destroyMethod != null) {
        invokeCustomDestroyMethod(this.destroyMethod);
    }
    else if (this.destroyMethodName != null) {
        Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);
        if (methodToInvoke != null) {
            invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));
        }
    }
}

bean 的销毁阶段生命周期回调的顺序:@PreDestroy → DisposableBean → destroy-method 。

处理bean中bean
// ......
    // Trigger destruction of contained beans...
    Set containedBeans;
    synchronized (this.containedBeanMap) {
        // Within full synchronization in order to guarantee a disconnected Set
        containedBeans = this.containedBeanMap.remove(beanName);
    }
    if (containedBeans != null) {
        for (String containedBeanName : containedBeans) {
            destroySingleton(containedBeanName);
        }
    }
    // ......

例如:


    
    
        
    

这种嵌套 bean ,就会记录在 DefaultSingletonBeanRegistry 的 containedBeanMap 中,既然外头的 bean 要销毁了,那里头的这些 bean 也就应该被销毁了,所以这里又是取到那些内部构造好的 bean ,依次递归调用 destroySingleton 方法来销毁这些 bean 。

销毁被依赖的bean
  // ......
    // Remove destroyed bean from other beans' dependencies.
    synchronized (this.dependentBeanMap) {
        for (Iterator>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry> entry = it.next();
            Set dependenciesToClean = entry.getValue();
            dependenciesToClean.remove(beanName);
            if (dependenciesToClean.isEmpty()) {
                it.remove();
            }
        }
    }

    // Remove destroyed bean's prepared dependency information.
    this.dependenciesForBeanMap.remove(beanName);
}

当自己销毁之后,那些依赖了当前 bean 的 bean 也就应该被销毁。套路都是一样的,取到那些被依赖的 bean 的名称,依次递归调用 destroySingleton 方法销毁。

关闭BeanFactory
// Close the state of this context itself.
closeBeanFactory();

说是关闭 BeanFactory ,实际上更接近于 “销毁” ,因为原来的 BeanFactory 无论如何都无法继续用了。

在基于 xml 和基于注解驱动的两种 ApplicationContext 的实现里,它们的策略既相似又不同:

// AbstractRefreshableApplicationContext
protected final void closeBeanFactory() {
    DefaultListableBeanFactory beanFactory = this.beanFactory;
    if (beanFactory != null) {
        beanFactory.setSerializationId(null);
        this.beanFactory = null;
    }
}

在基于 xml 配置文件的 ApplicationContext 中,它会获取到原有的 BeanFactory ,移除序列化 ID ,并直接丢弃原来的 BeanFactory 。

// GenericApplicationContext
protected final void closeBeanFactory() {
    this.beanFactory.setSerializationId(null);
}

在基于注解驱动的 ApplicationContext 中,它只会给内部组合的 BeanFactory 移除序列化 ID 而已。

GenericApplicationContext不允许被重复刷新的原因
rivate final AtomicBoolean refreshed = new AtomicBoolean();

protected final void refreshBeanFactory() throws IllegalStateException {
    if (!this.refreshed.compareAndSet(false, true)) {
        throw new IllegalStateException(
            "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    }

如果当前 GenericApplicationContext 是刚创建的,那么 refreshed 的值一定是 false ,此时使用 CAS 设置 true 是成功的,下面的 throw ex 动作不会执行;而第二次再调用 refresh 刷新 ApplicationContext 时,进入到该方法时,CAS 不通过,无法刷新 BeanFactory ,最终抛出异常。

剩余动作
  // ......
    // Let subclasses do some final clean-up if they wish...
    // 给子类用的,然而子类没一个重写的
    onClose();

    // Reset local application listeners to pre-refresh state.
    if (this.earlyApplicationListeners != null) {
        this.applicationListeners.clear();
        this.applicationListeners.addAll(this.earlyApplicationListeners);
    }

    // Switch to inactive.
    this.active.set(false);
}
总结:

bean 对象在销毁时,由 ApplicationContext 发起关闭动作。销毁 bean 的阶段,由 BeanFactory 取出所有单实例 bean ,并逐个销毁。

销毁动作会先将当前 bean 依赖的所有 bean 都销毁,随后回调自定义的 bean 的销毁方法,之后如果 bean 中有定义内部 bean 则会一并销毁,最后销毁那些依赖了当前 bean 的 bean 也一起销毁。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/349083.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号