前言

  之前将spring framework 源码导入了idea,后来折腾调试了一下,于是研究了一下最简单的singleton对象在spring中是如何创建的。这里所谓的简单,就是指无属性注入,无复杂构造函数的对象。

测试代码

  spring配置:

  1.   <bean id="userService" class="UserService" scope="singleton"></bean>
      测试类:
  1. public class UserService {
  2.  
  3. private final Log logger = LogFactory.getLog(getClass());
  4.  
  5. public UserService(){
  6. logger.info("UserService created");
  7. id = UUID.randomUUID().toString();
  8. }
  9.  
  10. private String id;
  11. public String getId(){
  12. return id;
  13. }
  14. public String getUserName(){
  15. return "xiaopanzi";
  16. }
  17. }

  

  1. public static void main(String[] args) {
  2. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  3. context.start();
  4. testNormalSingleton(context);
  5. }
  6.  
  7. private static void testCircleSingleton(ClassPathXmlApplicationContext context){
  8. SingletonAService aService = context.getBean("aService",SingletonAService.class);
  9. SingletonBService bService = context.getBean("bService",SingletonBService.class);
  10.  
  11. aService.getbService().print();
  12.  
  13. bService.getaService().print();
  14. }

调试详情

  首先在ApplicationContext 初始化过程,在 refresh 方法中会调用  finishBeanFactoryInitialization 方法,注释上也写的很明白:Instantiate all remaining (not-lazy-init) signletons。(初始化剩余的非懒加载的单例对象)。那么这里就是入口点。

  然后在调用 beanFactory.preInstantiateSingletons().

  后续调用链如下:

  DefaultListBeanFactory.getBean(beanName)

  AbstractBeanFactory.doGetBean(name,requiredType,args,typeCheckOnly)

  AbstractAutowireCapableBeanFactory.createBean(String beanName,RootBeanDefinition mbd,Object[] args)

       AbstractAutowireCapableBeanFactory.doCreateBean(String beanName,RootBeanDefinition mbd,Object[] args)

       AbstractAutowireCapableBeanFactory.instantiateBean(final String beanName, final RootBeanDefinition mbd)

       getInstantiationStrategy().instantiate(mbd, beanName, parent); (this.instantiationStrategy=CglibSubclassingInstantiationStrategy)

    SimpleInstantiationStrategy.instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) 

  BeanUtils.instantiateClass(Constructor<T> ctor, Object... args)

  通过上述代码调用链我们可以看出,最终的示例创建是由 BeanUtils.instantiateClass 方法完成的,也就是这个方法:

   

  1. public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
  2. Assert.notNull(ctor, "Constructor must not be null");
  3. try {
  4. ReflectionUtils.makeAccessible(ctor);
  5. return ctor.newInstance(args);
  6. }
  7. catch (InstantiationException ex) {
  8. throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
  9. }
  10. catch (IllegalAccessException ex) {
  11. throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
  12. }
  13. catch (IllegalArgumentException ex) {
  14. throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
  15. }
  16. catch (InvocationTargetException ex) {
  17. throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
  18. }
  19. }

  到此为止单例就创建完毕了。但是创建完成之后,还有后续的处理。

  DefaultSingletonBeanRegistry.addSingletonFactory(String beanName,ObjectFactory<?> singletonFactory);

  也就是将该示例放入到  singletonObjects 中,作为缓存方便后续取值。

  this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));

  当我们在次调用getBean的时候,那么在 DefaultSingletonBeanRegistry.getSingleton 方法中直接从 singletonObjects 中获取即可。

  1. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  2. Object singletonObject = this.singletonObjects.get(beanName);
  3. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  4. synchronized (this.singletonObjects) {
  5. singletonObject = this.earlySingletonObjects.get(beanName);
  6. if (singletonObject == null && allowEarlyReference) {
  7. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  8. if (singletonFactory != null) {
  9. singletonObject = singletonFactory.getObject();
  10. this.earlySingletonObjects.put(beanName, singletonObject);
  11. this.singletonFactories.remove(beanName);
  12. }
  13. }
  14. }
  15. }
  16. return (singletonObject != NULL_OBJECT ? singletonObject : null);
  17. }

  

总结

  上述内容记录的很少,基本就是一个轮廓的记录,要真正理解详情内容,还得自己去慢慢调试啊!!!

  

  

  1.  

  

Spring IoC 中的(Singleton)单例对象创建过程探索的更多相关文章

  1. Spring IOC(三)单例 bean 的注册管理

    Spring IOC(三)单例 bean 的注册管理 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 在 Spring 中 ...

  2. Singleton单例对象的使用

    namespace www{ public abstract class SingletonManager<T> : ISingletonManager where T : class, ...

  3. Spring IOC 容器源码分析 - 创建单例 bean 的过程

    1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...

  4. 不允许在单例对象中创建Srping容器

    spring.net在使用的时候,不允许在单例对象中创建Srping容器 需要将实例化模式转为单例singleton=“false”

  5. 从别人写的 Object-C 中 Singleton (单例) 模式 中的一些理解--备

    关于 面向对象的设计模式 对于面向对象的设计模式,想必大家并不陌生吧. 纵观23种设计模式中,数单例模式(Singleton)和工厂模式(Factory Method)最为熟悉和基础吧.当然,本文总结 ...

  6. 【cocos2d-js官方文档】二十五、Cocos2d-JS v3.0中的单例对象

    为何将单例模式移除 在Cocos2d-JS v3.0之前.全部API差点儿都是从Cocos2d-x中移植过来的,这是Cocos2d生态圈统一性的重要一环.可惜的是,这样的统一性也在非常大程度上限制了C ...

  7. atitit.guice3 绑定方式打总结生成非单例对象toInstance toProvider区别 v2 pb29

    atitit.guice3 绑定方式打总结生成非单例对象toInstance toProvider区别 v2 pb29 1. 三 绑定方式的介绍1 2. To接口,链式绑定,用的最多的1 3. toC ...

  8. OC中两种单例实现方式

    OC中两种单例实现方式 写在前面 前两天探索了一下C++ 的单例,领悟深刻了许多.今天来看看OC中的单例又是怎么回事.查看相关资料,发现在OC中一般有两种实现单例的方式,一种方式是跟C++ 中类似的常 ...

  9. 【Cocos2d-X游戏实战开发】捕鱼达人之单例对象的设计(二)

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为cocos2d-x-2.1.5)    博主发现前两个系列的学习教程被严重抄袭,在这里呼吁大家请尊重开发者的劳动成果, 转载的时候请务必注 ...

随机推荐

  1. (微信小程序)二 : 创建一个页面。

    首先先看一下pages的目录结构吧. 我创建了一个topics页面.3个文件全创建好了之后 我往topics.js添加数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

  2. Centos 从零开始 (三)

    8:连接阿里云. 需要用到 ssh指令进行远程登陆 [root@localhost ~]# service sshd start #如果没开启服务的话,需要开启服务. [root@localhost  ...

  3. 在WPF中自定义控件

    一, 不一定需要自定义控件在使用WPF以前,动辄使用自定义控件几乎成了惯性思维,比如需要一个带图片的按钮,但在WPF中此类任务却不需要如此大费周章,因为控件可以嵌套使用以及可以为控件外观打造一套新的样 ...

  4. 互联网轻量级框架SSM-查缺补漏第五天

    简言:这个地方我就草草过了,NBA圣诞大战,偷偷看比赛,真香~ 第五章映射器 5.2select元素 自动映射和驼峰映射:MyBatis提供了自动映射功能,在默认的情况下自动映射功能是开启的. 在se ...

  5. POJ1651 Multiplication Puzzle(相邻乘积之和最小,区间DP)

    http://blog.csdn.net/libin56842/article/details/9747021 http://www.cnblogs.com/devil-91/archive/2012 ...

  6. PAT 1034. Head of a Gang[bug]

    有一个两分的case出现段错误,真是没救了,估计是要写bfs的形式,可能栈溢出了 #include <cstdio> #include <cstdlib> #include & ...

  7. CakePHP redirect函数

    public function getContract($value=''){ App::uses ( 'UserContractController', 'Controller' ); $Contr ...

  8. 如何检测页面是否有重复的id属性值

    <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta nam ...

  9. [转]JSON.parse()和JSON.stringify()

    parse用于从一个字符串中解析出json对象,如 var str = '{"name":"huangxiaojian","age":&qu ...

  10. memset用法详解

    原文:http://www.cnblogs.com/PegasusWang/archive/2013/01/20/2868824.html 1.void *memset(void *s,int c,s ...