推荐阅读:

  • 手撕分布式技术:限流、通讯、缓存,全部一锅端走送给你
  • 秋招面试总结:Java+并发+Spring+MySQL+分布式+Redis+算法+JVM等
  • Spring全家桶笔记:Spring+Spring Boot+Spring Cloud+Spring MVC

BeanFactory & FactoryBean

说起Spring中的灵魂伴侣难道不是BeanFactory与FactoryBean吗?ta们两个不仅长相相似,在面试题目中更是形影不离,成双成对。然而事实上二者的关系就像生命中的过客,只是匆匆一眼,便相忘于江湖。 不过FactoryBean并不孤单,远处的ObjcetFactory遥遥相望,本文中并不准备详细解析这两个接口,不过读者可以把他们两个理解为指定类型Bean的孵化器,我们可以通过这两个接口改变Bean的初始化行为。但是二者还是有很大区别的。

BeanFactory & ApplicationContext

日常工作中我们常常将BeanFactory称为容器,而将ApplicationContext称为上下文。不知大家究竟有没有思考过二者之间的关系。Spring Aware接口家族一文中我曾详细阐释过如何获取当前运行环境中的BeanFactory、ApplicationContext,我们不妨在代码中找寻答案。

  • 配置类
package com.spring.container;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan("com.spring.container")public class ContainerConfig {}
  • 获取二者信息
package com.spring.container;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/** * @Author: Raphael */@Componentpublic class SpringIoc implements BeanFactoryAware, ApplicationContextAware {    @Override    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {        System.err.println(System.identityHashCode(beanFactory));        System.out.println(beanFactory.getClass().getName());    }    @Override    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        System.err.println(System.identityHashCode(applicationContext));        System.out.println(applicationContext.getClass().getName());    }}
  • 启动类
package com.spring.container;import org.springframework.context.annotation.AnnotationConfigApplicationContext;/** * @Author: Raphael */public class MainContainer {    public static void main(String[] args) {        AnnotationConfigApplicationContext context =                new AnnotationConfigApplicationContext(ContainerConfig.class);        context.close();    }}
  • 结果

显而易见二者不仅不是一个对象,类型都不一样。看到这里大多数人的认知已经破碎,因为潜意识中他们认为二者其实是一个事物。事实上人家甚至连继承关系都没有,直接打碎了另一波人的幻想。不信我们看看二者的UML类图。

几个容器?

敏锐的人其实已经发现了矛盾,认知中Spring的根容器应该有且只有一个才合理。但是这分明就是两个没有什么关联的对象啊。Spring官方文档如此论述二者的关系:

简而言之,BeanFactory提供了配置框架和基本功能,ApplicationContext增加了更多针对企业的功能。ApplicationContext是BeanFactory的一个完整的超集。

按照官方的解释:二者是一个包含与被包含的关系,那么在ApplicationContext中我们可以获得根容器吗? 上帝说:要有光,于是getAutowireCapableBeanFactory()就来了。

package com.spring.container;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.config.AutowireCapableBeanFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/** * @Author: Raphael */@Componentpublic class SpringIoc implements BeanFactoryAware, ApplicationContextAware {    private BeanFactory beanFactory;    @Override    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {        this.beanFactory = beanFactory;        System.err.println(System.identityHashCode(beanFactory));        System.out.println(beanFactory.getClass().getName());    }    // 直接打印两个对象的比对结果    @Override    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        AutowireCapableBeanFactory factory =                applicationContext.getAutowireCapableBeanFactory();        System.err.println(factory.hashCode());        System.out.println(factory.getClass().getName());        System.out.println("二者相等吗:    " + (factory == beanFactory));    }}

验证结果完全支持官方说明。

DefaultListableBeanFactory

官方对他如此定义:

Spring的{@link ConfigurableListableBeanFactory},{@link BeanDefinitionRegistry}的默认实现 成熟的bean工厂 基于bean定义元数据,可通过后处理器进行扩展

台前光亮的是BeanFactory,负重前行的却是DefaultListableBeanFactory,明明是三个人的电影,我却始终不能有姓名。那么DefaultListableBeanFactory的对象是何时产生的呢?一个新的问题又萦绕在我的心头。答案其实与IOC容器的初始化密不可分,我在这里不详叙了。我们只简单的剖析一下DefaultListableBeanFactory产生对象的心路历程。 我们在MainContainer中调用了如下构造方法:

public AnnotationConfigApplicationContext(Class>... annotatedClasses) {    this();    register(annotatedClasses);    refresh();}

因为AnnotationConfigApplicationContext继承了GenericApplicationContext,所以父类的的构造方法也会同时调用,容器对象就在此时诞生。

public GenericApplicationContext() {    this.beanFactory = new DefaultListableBeanFactory();}

然后refresh()调用obtainFreshBeanFactory()。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {    refreshBeanFactory();    return getBeanFactory();}

getBeanFactory()是AbstractApplicationContext定义的抽象方法。又由GenericApplicationContext实现。

public final ConfigurableListableBeanFactory getBeanFactory() {    return this.beanFactory;}

这里其实就是将自己构造方法产生的对象返回给AnnotationConfigApplicationContext。追踪到这一层的时候,容器对象的身世之谜才终于被我们揭开。其实ApplicationContext之所以有Beanfactory能力就是因为有关容器的操作他都委托给自己内部的容器对象了。举个例子:

public  T getBean(String name, Class requiredType) throws BeansException {    assertBeanFactoryActive();    return getBeanFactory().getBean(name, requiredType);}

这里实际上他并没有对此方法有详细的实现,而是通过getBeanFactory()获取自身内部的容器对象,然后交由ta实现。 现在脉络应该足够清晰了。Spring源码是设计模式的集大成者,这里其实运用的就是组合模式

二者差异

其实官方有他们二者的总结

org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基础。BeanFactory 接口提供了一种高级配置机制,能够管理任何类型的对象。 ApplicationContext 是其子接口。

增加了以下特性:

  • 与Spring的AOP功能轻松集成
  • 消息资源处理(用于国际化)
  • 活动发布
  • 应用层特定的上下文

作者:颜如玉
链接:https://juejin.im/post/5e3ea6c16fb9a07cb427c5b4

中getname_Spring IOC中的灵魂伴侣:BeanFactory ApplicationContext相关推荐

  1. 请解释下Spring 框架中的IOC 容器?

    Spring 中的org.springframework.beans 包和org.springframework.context 包构成了Spring 框架IOC 容器的基础. BeanFactory ...

  2. java spring server_Java server框架之(1):spring中的IoC

    为什么需要IoC? 一般的对象耦合是在编译时确定的,也就是说当我们写如下类: 1 public classStaticCoupling { 2 3 String s = new String(&quo ...

  3. java spring server_java server之spring中的IOC如何用java实现?

    ** 什么是IOC? 一般的对象耦合是在编译时确定的,也就是说当我们写如下类: public class StaticCoupling { String s = new String("hz ...

  4. Spring中的IOC介绍

    Spring中的IOC介绍 IOC(控制反转) IOC介绍 IOC是什么 IOC能做什么 Spring容器管理对象 1.maven管理依赖 2.给定容器的配置文件 3.IOC容器管理对象 4.通过容器 ...

  5. java中ioc作用_Spring中的IOC是什么意思,为什么要用IOC而不是New来创建实例?

    这里是修真院后端小课堂,每篇分享文从 [背景介绍][知识剖析][常见问题][解决方案][编码实战][扩展思考][更多讨论][参考文献] 八个方面深度解析后端知识/技能,本篇分享的是: [Spring中 ...

  6. Spring中的IOC容器原理

    什么是IOC: IOC(Inverse of Control)控制反转,将对象的创建权利反转给Spring框架. 它是面向对象编程中的一种设计原则,可以用来降低计算机代码之间的耦合度. IOC容器的底 ...

  7. Spring中的IoC(控制反转)和DI(依赖注入)

    一.Spring IoC的基本概念 控制反转(IoC) 是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心. 依赖注入(DI) 是IoC的另外一种说法,只是从不同的角度 ...

  8. 用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)

    用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心. 依赖注入(DI) ...

  9. Springc中的IOC控制反转c01

    一.IoC(控制反转)基本概念 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(D ...

最新文章

  1. 习题10-2 递归求阶乘和 (15 分)
  2. oracle不能用uuid,Oracle 应用之--VirtualBox UUID问题
  3. javascript +new Date()
  4. 用java编写打印时间_编写一个java程序,读取系统时间,然后将时间用中文输出...
  5. EmguCV 一些基本操作
  6. 蓝桥杯历届试题----矩阵翻硬币
  7. 测试markdown的发布
  8. C++学习 —— 灵活的继承特性【C++不是玩具,而是生产工具】
  9. python+webdriver(三)
  10. deap dataset的不同分类模型的实现(1)
  11. Log:日志选型调研『一』
  12. 房贷新政刺激换房需求 北京楼市成交量反弹
  13. 256K,320K及以上Nero AAC,QAAC,FAAC,MP3,OGG等主流有损音频格式横评
  14. html文档在word打开是乱码怎么解决,word打开是乱码怎么办?怎么解决
  15. 贝叶斯分类器,什么是朴素贝叶斯,后续为使用贝叶斯实现海量数据的邮件筛选。带源码数据集和解决思路
  16. 一文说清MySQL索引数据结构
  17. 怎样将微信热门文章采集到自己的公众号中?
  18. 电脑蓝屏了怎么办修复,电脑蓝屏解决修复方法
  19. Scrapy新手入门
  20. jdbc是什么(jdbc是什么设计模式)

热门文章

  1. Spring MVC和Struts2
  2. Dynamips 简介
  3. 如果打回车来更新模板列中的TEXTBOX
  4. 决策树—ID3(源码解析)
  5. ASP.NET中进行消息处理(MSMQ) 三
  6. 工作组模式下专用队列(Private Queue)如何引用远程队列路径
  7. 从Web借鉴UI设计
  8. Request.InputStream 将数据作为XML数据发送
  9. 学习 WCF (3)--开发WCF客户程序
  10. Mysql-innoDB存储引擎(事务,锁,MVCC)