博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
获取单例
阅读量:4957 次
发布时间:2019-06-12

本文共 5420 字,大约阅读时间需要 18 分钟。

前言

上一篇文章讲述了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例bean,就需要重新开始加载bean的所有过程了,这篇文章讲述的就是从头开始加载bean的过程中的一个步骤---获取单例。

获取单例

Spring中使用getSingleton的重载方法实现bean的加载过程,在getBean方法源码中体现:

      sharedInstance = getSingleton(beanName, () -> {                        try {                            return createBean(beanName, mbd, args);                        }                        catch (BeansException ex) {                            destroySingleton(beanName);                            throw ex;                        }                    });

 来看一下getSingleton方法的源码:

public Object getSingleton(String beanName, ObjectFactory
singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); //全局变量需要同步 synchronized (this.singletonObjects) { //首先检查对应的bean是否被加载过,因为singleton模式其实就是复用以前创建的bean,所以这一步是必须的 Object singletonObject = this.singletonObjects.get(beanName); //如果为空才可以进行singleton的bean初始化 if (singletonObject == null) { //当工厂的单例对象处于销毁状态时,不允许创建单例bean if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { //初始化bean singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { //加入缓存 addSingleton(beanName, singletonObject); } } return singletonObject; } }

 上述代码其实是使用了回调方法,使得程序在单例创建的前后做一些准备及处理操作,而真正的获得单例bean的方法其实并不是在此方法中实现的,其实逻辑是在ObjectFactory类的实例singletonFactory中实现的。上述代码的处理操作包括如下几步:

(1)检查缓存是否已经加载过;

(2)若没有加载,则记录beanName的状态为正在加载状态;

(3)加载单例前记录加载状态;

  其中beforeSingletonCreation(beanName),为空实现,里面没有任何逻辑,其实不是,这个方法中做了一个重要的操作:记录加载状态,也就是通过this.singletonsCurrentlyInCreation.add(beanName)将当前正要创建的bean记录在缓存中,这样便可以对循环依赖进行检测:

protected void beforeSingletonCreation(String beanName) {        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {            throw new BeanCurrentlyInCreationException(beanName);        }    }

(4)通过调用参数传入的ObjectFactory的个体Object方法实例化bean;

(5)加载单例后的处理方法调用。

  与步骤(3)的记录加载状态相似,当bean加载结束后需要移除缓存中对该bean正在加载状态的记录。

protected void afterSingletonCreation(String beanName) {        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");        }    }

(6)将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态;

protected void addSingleton(String beanName, Object singletonObject) {        synchronized (this.singletonObjects) {            this.singletonObjects.put(beanName, singletonObject);            this.singletonFactories.remove(beanName);            this.earlySingletonObjects.remove(beanName);            this.registeredSingletons.add(beanName);        }    }

(7)返回处理结果。

上述代码的处理过程就到这里结束了。

总结:虽然我们已经从外部了解了加载bean的逻辑架构,但我们现在还没有开始对bean加载功能的探索,之前的文章提到过,bean的加载逻辑其实是在传入的ObjectFactory类的参数singletonFactory中定义的,我们反推参数的获取,得到如下代码:

sharedInstance = getSingleton(beanName, new ObjectFactory{    public Object getObject() thows BeansWxception{                        try {                            return createBean(beanName, mbd, args);                        }         }                        catch (BeansException ex) {                            destroySingleton(beanName);                            throw ex;                        }                    });

ObjectFactory的核心部分其实只是调用了createBean方法,所以接下来我们还需要到createBean中去追寻bean的加载过程。

参考:《Spring源码深度解析》 郝佳 编著:

转载于:https://www.cnblogs.com/Joe-Go/p/10148033.html

你可能感兴趣的文章
ubuntu下如何查看用户登录及系统授权相关信息
查看>>
丶制作一个数字猜猜看小游戏
查看>>
秋季学期学习总结
查看>>
SpringBoot 优化内嵌的Tomcat
查看>>
【LaTeX】E喵的LaTeX新手入门教程(1)准备篇
查看>>
highcharts曲线图
查看>>
extjs动态改变样式
查看>>
PL/SQL Developer 查询的数据有乱码或者where 字段名=字段值 查不出来数据
查看>>
宏定义
查看>>
ubuntu12.04 串口登录系统配置
查看>>
poj3061
查看>>
linux--多进程进行文件拷贝
查看>>
笔记:git基本操作
查看>>
.net开发工作中遇到的问题(附带解决方案)(持续记录)
查看>>
ajax 请求数据
查看>>
k8s-部署WEB-UI(dashboard)
查看>>
linux常用命令
查看>>
推荐 30 款最好的免费项目管理软件
查看>>
SDN第五次上机作业
查看>>
leetcode 657. Judge Route Circle
查看>>