首先看一张时序图

最开始,一切都来自这里:

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext3.xml");
		context.getBean("newsBean"); 

	}

如果我们是通过BeanFactory来构造IoC容器的话,那就是直接从上面的时序图的第五步开始

[java] view
plain
copy

  1. public static  void main(String[] args){
  2. Resource resource=new ClassPathResource("applicationContext2.xml");
  3. BeanFactory factory=new DefaultListableBeanFactory();
  4. BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
  5. bdr.loadBeanDefinitions(resource);
  6. String url=((FXNewsBean) factory.getBean("newsBean2")).getUrl();
  7. System.out.println(url);
  8. }

当然,ApplicatonContext有缓存机制,在容器启动的时候,就加载了所有的bean,并缓存之,如果有了显式或隐式的调用,直接从缓存里拿就是了

********************

我们从上面的代码很容易追踪到AbstractBeanFactory的doGetBean方法

[java] view
plain
copy

  1. @SuppressWarnings("unchecked")
  2. protected <T> T doGetBean(
  3. final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
  4. throws BeansException {
  5. //*************************1
  6. final String beanName = transformedBeanName(name);
  7. Object bean;
  8. // Eagerly check singleton cache for manually registered singletons.
  9. //*************************2
  10. Object sharedInstance = getSingleton(beanName);
  11. if (sharedInstance != null && args == null) {
  12. if (logger.isDebugEnabled()) {
  13. if (isSingletonCurrentlyInCreation(beanName)) {
  14. logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
  15. "' that is not fully initialized yet - a consequence of a circular reference");
  16. }
  17. else {
  18. logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
  19. }
  20. }
  21. //判断要获得的bean是否实现了FactoryBean,是获得工厂本身还是获得工厂生产的产品
  22. //如果要获得工厂本身 beanName就要以&开头
  23. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  24. }
  25. else {
  26. // Fail if we're already creating this bean instance:
  27. // We're assumably within a circular reference.
  28. //下面这个是关于循环依赖的处理
  29. if (isPrototypeCurrentlyInCreation(beanName)) {
  30. throw new BeanCurrentlyInCreationException(beanName);
  31. }
  32. // Check if bean definition exists in this factory.
  33. //如果存在父容器,且当前容器中不存在要获取的对象 那就去父容器去找
  34. BeanFactory parentBeanFactory = getParentBeanFactory();
  35. if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
  36. // Not found -> check parent.
  37. String nameToLookup = originalBeanName(name);
  38. if (args != null) {
  39. // Delegation to parent with explicit args.
  40. return (T) parentBeanFactory.getBean(nameToLookup, args);
  41. }
  42. else {
  43. // No args -> delegate to standard getBean method.
  44. return parentBeanFactory.getBean(nameToLookup, requiredType);
  45. }
  46. }
  47. //typeCheckOnly参数 调用是就是false
  48. //标明这个beanname已经被创建了
  49. //后面会用到
  50. if (!typeCheckOnly) {
  51. markBeanAsCreated(beanName);
  52. }
  53. //*************************3
  54. final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  55. checkMergedBeanDefinition(mbd, beanName, args);
  56. // Guarantee initialization of beans that the current bean depends on.
  57. //*************************4
  58. String[] dependsOn = mbd.getDependsOn();
  59. if (dependsOn != null) {
  60. for (String dependsOnBean : dependsOn) {
  61. getBean(dependsOnBean);
  62. registerDependentBean(dependsOnBean, beanName);
  63. }
  64. }
  65. // Create bean instance.
  66. //*************************5
  67. if (mbd.isSingleton()) {
  68. sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
  69. public Object getObject() throws BeansException {
  70. try {
  71. return createBean(beanName, mbd, args);
  72. }
  73. catch (BeansException ex) {
  74. // Explicitly remove instance from singleton cache: It might have been put there
  75. // eagerly by the creation process, to allow for circular reference resolution.
  76. // Also remove any beans that received a temporary reference to the bean.
  77. destroySingleton(beanName);
  78. throw ex;
  79. }
  80. }
  81. });
  82. bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  83. }
  84. else if (mbd.isPrototype()) {
  85. // It's a prototype -> create a new instance.
  86. Object prototypeInstance = null;
  87. try {
  88. beforePrototypeCreation(beanName);
  89. prototypeInstance = createBean(beanName, mbd, args);
  90. }
  91. finally {
  92. afterPrototypeCreation(beanName);
  93. }
  94. bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
  95. }
  96. else {
  97. String scopeName = mbd.getScope();
  98. final Scope scope = this.scopes.get(scopeName);
  99. if (scope == null) {
  100. throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
  101. }
  102. try {
  103. Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
  104. public Object getObject() throws BeansException {
  105. beforePrototypeCreation(beanName);
  106. try {
  107. return createBean(beanName, mbd, args);
  108. }
  109. finally {
  110. afterPrototypeCreation(beanName);
  111. }
  112. }
  113. });
  114. bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
  115. }
  116. catch (IllegalStateException ex) {
  117. throw new BeanCreationException(beanName,
  118. "Scope '" + scopeName + "' is not active for the current thread; " +
  119. "consider defining a scoped proxy for this bean if you
    "+
  120. "intend to refer to it from a singleton",
  121. ex);
  122. }
  123. }
  124. }
  125. // Check if required type matches the type of the actual bean instance.
  126. if (requiredType != null && bean != null &&
  127. !requiredType.isAssignableFrom(bean.getClass())) {
  128. try {
  129. return getTypeConverter().convertIfNecessary(bean, requiredType);
  130. }
  131. catch (TypeMismatchException ex) {
  132. if (logger.isDebugEnabled()) {
  133. logger.debug("Failed to convert bean '" + name +
  134. "' to required type [" +
  135. ClassUtils.getQualifiedName(requiredType) + "]", ex);
  136. }
  137. throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
  138. }
  139. }
  140. return (T) bean;
  141. }

代码1处,转化有两个步骤,首先处理beanName为&XXX的格式,这里表示要取指定name的factoryBean。在这里先把&符号取消,先获取bean再处理。然后,针对bean的alias机制,这里传入的参数可能是一个bean别名,那么我们先获取这个bean的主要id,只需要根据id值取bean就可以了。

代码2处,就是依次检查缓存。如果缓存里有,就直接拿出来。

    spring的缓存有3种

    之前已经获取过的bean

    手动注入的bean

    手动注入的ObjectFactory

第一种缓存好理解,看一下下面的代码,大家就知道手动注入bean与ObjectFctory是怎么回事了。

[java] view
plain
copy

  1. public static  void main(String[] args){
  2. Resource resource=new ClassPathResource("applicationContext2.xml");
  3. BeanFactory factory=new DefaultListableBeanFactory();
  4. BeanDefinitionReader bdr=new XmlBeanDefinitionReader(
  5. (BeanDefinitionRegistry) factory);
  6. bdr.loadBeanDefinitions(resource);
  7. FXNewsBean fx=new FXNewsBean();
  8. fx.setUrl("Thank glt");
  9. //同时还有一个方法叫addSingletonFactory
  10. ((DefaultSingletonBeanRegistry) factory).registerSingleton("newsBean2",fx);
  11. FXNewsBean news=(FXNewsBean) factory.getBean("newsBean2");
  12. System.out.println(news.getUrl());  //打印出Thank glt
  13. }
[java] view
plain
copy

  1. final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
  2. checkMergedBeanDefinition(mbd, beanName, args);

代码3处,麻烦的是是getMergedLocalBeanDefinition(beanName)。这个处理的主要是bean的present信息与scope信息。

说实话,这部分我没有看。

下面就是检查bean了。

首先,这个bean不能是abstract的。其次,如果getBean时还传递了要获取bean的参数(这里指构造方法的参)并且这个bean是singleton,那就得报错。

为什么?你想呀

factory.getBean("myBean","aaaa");

factory.getBean("myBean","bbbb");

如果myBean这个对象是singleton,上面的两行代码获得的对象能相等吗?

所以只能报错了。

[java] view
plain
copy

  1. String[] dependsOn = mbd.getDependsOn();
  2. if (dependsOn != null) {
  3. for (String dependsOnBean : dependsOn) {
  4. getBean(dependsOnBean);
  5. registerDependentBean(dependsOnBean, beanName);
  6. }
  7. }

代码4处,如果BeanA中引用了BeanB,那么再getBean("BeanA")时就会先getBean("BeanB");

之后,注册依赖关系。

这个依赖关系有什么用呢?

似乎是在销毁类时用的,我不是很清楚。















代码5

如果要获取的bean是单例的

[java] view
plain
copy

  1. if (mbd.isSingleton()) {
  2. sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
  3. public Object getObject() throws BeansException {
  4. try {
  5. return createBean(beanName, mbd, args);
  6. }
  7. catch (BeansException ex) {
  8. // Explicitly remove instance from singleton cache: It might have been put there
  9. // eagerly by the creation process, to allow for circular reference resolution.
  10. // Also remove any beans that received a temporary reference to the bean.
  11. destroySingleton(beanName);
  12. throw ex;
  13. }
  14. }
  15. });
  16. }

注意上面的代码其实只有一行。

即调用getSingleton方法。

只不过getSingleton的第二个参数是一个匿名内部类。

这个内部类有一个getObject方法。,里面调用的是外部类的方法createBean。(外部类是谁?是AbstractBeanFactory)

我们先看getSingleton

[java] view
plain
copy

  1. public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
  2. singletonObject = singletonFactory.getObject();
  3. addSingleton(beanName, singletonObject);//添加到已成功创建列表中 这是缓存
  4. return (singletonObject != NULL_OBJECT ? singletonObject : null);
  5. }

getSingleton省略了一些代码,主要是验证

getSingleton里面调用getObject就跑到了匿名类里面,最后的是AbstractBeanFactory的createBean方法。

不过AbstractBeanFactory中creatBean是abstract的。

实现在它的子类----AbstractAutowireCapableBeanFactory

[java] view
plain
copy

  1. @Override
  2. protected Object createBean(final String beanName,
  3. final RootBeanDefinition mbd, final Object[] args)
  4. throws BeanCreationException {
  5. if (logger.isDebugEnabled()) {
  6. logger.debug("Creating instance of bean '" + beanName + "'");
  7. }
  8. // Make sure bean class is actually resolved at this point.
  9. //*************************5.1  保证RootBeanDefinition里面有beanclass
  10. resolveBeanClass(mbd, beanName);
  11. // Prepare method overrides.
  12. try {
  13. //*************************5.2  方法注入
  14. mbd.prepareMethodOverrides();
  15. }
  16. catch (BeanDefinitionValidationException ex) {
  17. throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
  18. beanName, "Validation of method overrides failed", ex);
  19. }
  20. try {
  21. // Give BeanPostProcessors a chance to return
  22. // a proxy instead of the target bean instance.
  23. //*************************5.3
  24. Object bean = resolveBeforeInstantiation(beanName, mbd);
  25. if (bean != null) {
  26. return bean;
  27. }
  28. }
  29. catch (Throwable ex) {
  30. throw new BeanCreationException(
  31. mbd.getResourceDescription(), beanName,
  32. "BeanPostProcessor before instantiation of bean failed", ex);
  33. }
  34. //*************************5.4
  35. Object beanInstance = doCreateBean(beanName, mbd, args);
  36. if (logger.isDebugEnabled()) {
  37. logger.debug("Finished creating instance of bean '" + beanName + "'");
  38. }
  39. return beanInstance;
  40. }

关于5.2处的代码,它处理的类似这样的bean。 更多信息可查看 http://blog.csdn.net/dlf123321/article/details/47862175

[java] view
plain
copy

  1. <bean id="mockPersister" class="..impl.MockNewsPersister">
  2. <lookup-method name="getNewsBean" bean="newsBean"/>
  3. </bean>

关于5.3处的代码,得提到一个接口InstantiationAwareBeanPostProcessor,它本身也继承了BeanPostProcessor接口。

我们看到了在5.3代码的下面一旦resolveBeforeInstantiation的返回值不是null,那么直接就return。

resolveBeforeInstantiation类似于一个"短路器",执行了resolveBeforeInstantiation后(我是指getBean的对象实现了InstantiationAwareBeanPostProcessor接口,并且postProcessBeforeInstantiation方法的返回值不为null)下面的流程就不走了,直接返回bean。

这个方法一般情况下返回的都是null,通常情况下都是Spring容器内部使用这种特殊类型的BeanPostProcessor做一些动态对象代理等工作,我们使用普通的BeanPostProcessor实现就可以。这里简单提及一下,目的是让大家有所了解。





历尽千辛万苦,我们终于到了5.4了

让我歇会,下一节我们聊doCreatBean。



Spring BeanFacoty doCreateBean方法分析





参考资料

http://michael-softtech.iteye.com/blog/816469 spring源码分析之——spring bean的获取

http://www.iflym.com/index.php/code/201208290001.html Spring中获取一个bean的流程-1

<<spring揭秘>> 第四章 79页

版权声明:本文为博主原创文章,未经博主允许不得转载。

Spring BeanFactory getBean 源码剖析的更多相关文章

  1. Spring源码剖析依赖注入实现

    Spring源码剖析——依赖注入实现原理 2016年08月06日 09:35:00 阅读数:31760 标签: spring源码bean依赖注入 更多 个人分类: Java   版权声明:本文为博主原 ...

  2. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...

  3. Spring 源码剖析IOC容器(一)概览

    目录 一.容器概述 二.核心类源码解读 三.模拟容器获取Bean ======================= 一.容器概述 spring IOC控制反转,又称为DI依赖注入:大体是先初始化bean ...

  4. Spring源码剖析9:Spring事务源码剖析

    转自:http://www.linkedkeeper.com/detail/blog.action?bid=1045 声明式事务使用 Spring事务是我们日常工作中经常使用的一项技术,Spring提 ...

  5. Spring源码剖析3:Spring IOC容器的加载过程

    本文转自五月的仓颉 https://www.cnblogs.com/xrq730 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https ...

  6. Spring源码剖析2:初探Spring IOC核心流程

    本文转载自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutor ...

  7. Spring源码剖析4:懒加载的单例Bean获取过程分析

    本文转自五月的仓颉 https://www.cnblogs.com/xrq730 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https ...

  8. Spring IOC 容器源码分析

    声明!非原创,本文出处 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 S ...

  9. Spring IOC 容器源码分析(转)

    原文地址 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢 ...

随机推荐

  1. Python 3.3.2 round函数并非"四舍五入"

    对于一些貌似很简单常见的函数,最好还是去读一下Python文档,否则当你被某个BUG折磨得死去活来时,还不知根源所在.尤其是Python这种不断更新的语言.(python 2.7 的round和3.3 ...

  2. 安卓onTextChanged参数解释及实现EditText字数监听 Editable使用

    原作者部分修改部分 补充部分 补充部分2 补充部分3 补充部分4 Editable 尊重原作者:此篇文章是借鉴原作者地址 的博文 并进行修改和增加补充说明,我只是补充和修改: 我感觉这篇文章经过我的补 ...

  3. springMVC源码分析--HandlerAdapter(一)

    HandlerAdapter的功能实际就是执行我们的具体的Controller.Servlet或者HttpRequestHandler中的方法. 类结构如下:

  4. Android Studio 2.2 新功能详解

    Tamic /文 -译 http://blog.csdn.net/sk719887916/article/details/52672688 Android的Studio 2.2 已经可以在官网下载了. ...

  5. main函数之后的调用

    main函数代表进程的主线程.程序开始执行时,系统为程序创建一个进程,main函数其实并不是首先被调用的函数,而是操作系统调用了C/C++运行期启动函数,该函数负责对C/C++ 运行期库进行初始化.它 ...

  6. Android Multimedia框架总结(十三)CodeC部分之OpenMAX框架初识及接口与适配层实现

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52629598 前言:上篇中介绍O ...

  7. ssh远程登录操作 和ssh信任

    ssh 可以参考上一篇telnet的文章 1.安装openssh-server     sudo dpkg -i openssh-client_1%3a5.5p1-4ubuntu6_i386.deb ...

  8. SQL Server 执行计划操作符详解(1)——断言(Assert)

    前言: 很多很多地方对于语句的优化,一般比较靠谱的回复即使--把执行计划发出来看看.当然那些只看语句就说如何如何改代码,我一直都是拒绝的,因为这种算是纯蒙.根据本人经验,大量的性能问题单纯从语句来看很 ...

  9. UNIX网络编程——原始套接字的魔力【上】

    基于原始套接字编程 在开发面向连接的TCP和面向无连接的UDP程序时,我们所关心的核心问题在于数据收发层面,数据的传输特性由TCP或UDP来保证: 也就是说,对于TCP或UDP的程序开发,焦点在Dat ...

  10. EBS接口程序调试

    这两天在做采购接收的时候有一个香港的业务实体的采购接不进去,但是其他业务实体能接进去,找错误话费了不少时间,也参考了网上好多资料,虽然最后这个方法没用但觉得还是很有用的,整理一下作为自己的一个总结 错 ...