BeanFactory和FactoryBean的区别

2023-11-17

区别:

https://liayun.blog.csdn.net/article/details/110391066
BeanFactory是个Factory,也就是IOC容器或对象工厂,
而FactoryBean就是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。

但对FactoryBean而言,这个Bean不是简单的Bean,FactoryBean是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

FactoryBean 的源码分析;
在这里插入图片描述

FactoryBean概述

一般情况下,Spring是通过反射机制利用bean的class属性指定实现类来实例化bean的。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,那么则需要在标签中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可以得到一个更加简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

FactoryBean接口对于Spring框架来说占有非常重要的地位,Spring自身就提供了70多个FactoryBean接口的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring 3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean的形式。
在这里插入图片描述

当配置文件中标签的class属性配置的实现类是FactoryBean时,通过 getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

FactoryBean案例

首先,创建一个ColorFactoryBean类,它得实现FactoryBean接口,如下所示。

package com.meimeixia.bean;

import org.springframework.beans.factory.FactoryBean;

/**
 * 创建一个Spring定义的FactoryBean
 * T(泛型):指定我们要创建什么类型的对象
 * @author liayun
 * 
 */
public class ColorFactoryBean implements FactoryBean<Color> {

	// 返回一个Color对象,这个对象会添加到容器中
	@Override
	public Color getObject() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("ColorFactoryBean...getObject...");
		return new Color();
	}

	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Color.class; // 返回这个对象的类型
	}

	// 是单例吗?
	// 如果返回true,那么代表这个bean是单实例,在容器中只会保存一份;
	// 如果返回false,那么代表这个bean是多实例,每次获取都会创建一个新的bean
	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return false;
	}

}

然后,我们在MainConfig2配置类中加入ColorFactoryBean的声明,如下所示。

package com.meimeixia.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Lazy;

import com.meimeixia.bean.Color;
import com.meimeixia.bean.ColorFactoryBean;
import com.meimeixia.bean.Person;
import com.meimeixia.bean.Red;
import com.meimeixia.condition.LinuxCondition;
import com.meimeixia.condition.MyImportBeanDefinitionRegistrar;
import com.meimeixia.condition.MyImportSelector;
import com.meimeixia.condition.WindowsCondition;

// 对配置类中的组件进行统一设置
@Conditional({WindowsCondition.class}) // 满足当前条件,这个类中配置的所有bean注册才能生效
@Configuration
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) // @Import快速地导入组件,id默认是组件的全类名
public class MainConfig2 {
	
	@Lazy
	@Bean("person")
	public Person person() {
		System.out.println("给容器中添加咱们这个Person对象...");
		return new Person("美美侠", 25);
	}

	@Bean("bill")
	public Person person01() {
		return new Person("Bill Gates", 62);
	}
	
	@Conditional({LinuxCondition.class})
	@Bean("linus")
	public Person person02() {
		return new Person("linus", 48);
	}

	@Bean
	public ColorFactoryBean colorFactoryBean() {
		return new ColorFactoryBean();
	}
	
}

这里需要小伙伴们注意的是:我在这里使用@Bean注解向Spring容器中注册的是ColorFactoryBean对象。

那现在我们就来看看Spring容器中到底都有哪些bean。我们所要做的事情就是,运行IOCTest类中的testImport()方法,此时,输出的结果信息如下所示。
在这里插入图片描述
可以看到,结果信息中输出了一个colorFactoryBean,我们看下这个colorFactoryBean到底是个什么鬼!此时,我们对IOCTest类中的testImport()方法稍加改动,添加获取colorFactoryBean的代码,并输出colorFactoryBean实例的类型,如下所示。

@Test
public void testImport() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
        System.out.println(name);
    }
    
    // 工厂bean获取的是调用getObject方法创建的对象
    Object bean2 = applicationContext.getBean("colorFactoryBean");
    System.out.println("bean的类型:" + bean2.getClass());

}

再次运行IOCTest类中的testImport()方法,发现输出的结果信息如下所示。
在这里插入图片描述
可以看到,虽然我在代码中使用@Bean注解注入的是ColorFactoryBean对象,但是实际上从Spring容器中获取到的bean对象却是调用ColorFactoryBean类中的getObject()方法获取到的Color对象。

如何在Spring容器中获取到FactoryBean对象本身呢?
在这里插入图片描述

看到这里,是不是明白了呢?没错,在BeanFactory接口中定义了一个&前缀,只要我们使用bean的id来从Spring容器中获取bean时,Spring就会知道我们是在获取FactoryBean本身。

BeanFactory概述

1、简单介绍

这个其实是所有Spring Bean的容器根接口,给Spring 的容器定义一套规范,给IOC容器提供了一套完整的规范,比如我们常用到的getBean方法等。

进入到这个类,我们可以看到如下注释,意思是:访问Spring bean容器的根接口。
在这里插入图片描述

2、定义方法

  • getBean(String name): Spring容器中获取对应Bean对象的方法,如存在,则返回该对象。
  • containsBean(String name):判断Spring容器中是否存在该对象。
  • isSingleton(String name):通过beanName判断是否为单例对象。
  • isPrototype(String name):判断bean对象是否为多例对象。
  • isTypeMatch(String name, ResolvableType typeToMatch):判断name值获取出来的bean与typeToMath是否匹配。
  • getType(String name):获取Bean的Class类型。
  • getAliases(String name):获取name所对应的所有的别名。

3、主要实现类(包括抽象类)

  • AbstractBeanFactory:抽象Bean工厂,绝大部分的实现类,都是继承于它。
  • DefaultListableBeanFactory:Spring默认的工厂类。
  • XmlBeanFactory:前期使用XML配置用的比较多的时候用的Bean工厂。
  • AbstractXmlApplicationContext:抽象应用容器上下文对象。
  • ClassPathXmlApplicationContext:XML解析上下文对象,用户创建Bean对象我们早期写Spring的时候用的就是它。
    #FFFFE4

4、使用方式

BeanFactory的使用方式有很多,这里就不一一列举了,具体请查看源码。

举一个简单的例子,使用ClassPathXmlApplicationContext读取对应的xml文件实例对应上下文对象:

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
BeanFactory factory = (BeanFactory) context;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

BeanFactory和FactoryBean的区别 的相关文章

随机推荐

  • 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?实现 int sqrt(int x) 函数。

    今天我们来爬一爬楼梯 假设你正在爬楼梯 需要 n 阶你才能到达楼顶 每次你可以爬 1 或 2 个台阶 你有多少种不同的方法可以爬到楼顶呢 注意 给定 n 是一个正整数 示例 1 输入 2 输出 2 解释 有两种方法可以爬到楼顶 1 阶 1
  • 为啥 Python 运行速度这么慢 ?

    作者 Anthony Shaw 是 Python 软件基金会成员和 Apache 基金会成员 近来Python可谓人气骤升 这门编程语言用于开发运维 DevOps 数据科学 网站开发和安全 然而 它没有因速度而赢得任何奖牌 Java在速度方
  • javascript防抖(Debouncing)和节流阀(Throttling)

    中文原文链接 https jinlong github io 2016 04 24 Debouncing and Throttling Explained Through Examples 英文原文链接 https css tricks c
  • C++ 生命周期

    C 程序的生命周期要经过编码 Coding 预处理 Pre processing 编译 Compiling 和运行 Running 四个阶段 编码即coding阶段 这阶段主要是定义变量 写语句 实现各种数据结构 函数和类 预处理是 C C
  • Qt::带返回值的信号发射方式

    一般来说 我们发出信号使用emit这个关键字来操作 但是会发现 emit并不算一个调用 所以它没有返回值 那么如果我们发出这个信号想获取一个返回值怎么办呢 两个办法 1 通过出参形式返回 引用或者指针的方式带回 比如emit sig int
  • 【SHELL脚本】MYSQLDUMP备份数据库,含忽略数据表

    背景介绍 项目的数据库十分重要 必须保证数据不能丢失 项目组的数据库为mysql5 7 12 采用备份工具mysqldump 开发需求 备份指定多个数据库 部分数据库的部分数据表需要指定忽略 打包上传到go FastDFS文件管理器 下面为
  • jvm 内存分配

    1 任何对象都是以8字节为粒度进行对齐的 2 类属性按照如下优先级进行排列 长整型和双精度类型 8字节 整型和浮点型 4字节 字符和短整型 2字节 字符类型和布尔类型 1字节 最后时引用类型 3 不同类型继承关系类的成员不能混合排列 首先按
  • 程序员究竟还需要读书么?

    近来看了2篇和读书有关的文章 一篇提到Joel讲现在程序员不太读书了 主要靠在网上找各种参考资料 一篇则是马总说的 成功与情商有关 与读书多少关系不大 一定程度上这两个观点都有点道理 可以靠StackOverflow com和搜索引擎找到各
  • 1 FFmpeg从入门到精通-FFmpeg简介

    1 FFmpeg从入门到精通 FFmpeg简介 2 FFmpeg从入门到精通 FFmpeg工具使用基础 3 FFmpeg从入门到精通 FFmpeg转封装 4 FFmpeg从入门到精通 FFmpeg转码 5 FFmpeg从入门到精通 FFmp
  • 一个人开发APP系列之实战1 制作APP产品启动图标

    声明 写这个博客系列也是为了清晰思路 新手写的不好 请大神们指导指导 建议想学的还是先去android develops官网看看相关资料吧 好了 不闲扯了 进入正题 今天的目的是使用Android Studio自带的工具Image Asse
  • TencentOS-tiny 功耗管理 (二十 二)- tickless(低功耗)

    一 功耗管理 tickless 概述 TencentOS tiny的tickless机制提供了一套非周期性时钟的方案 在系统无需systick驱动调度的情况下 停掉systick 初级功耗管理方案下 因为还有系统systick的存在 因此系
  • python机器人编程——差速AGV机器、基于视觉和预测控制的循迹、自动行驶(下篇)

    目录 一 前言 二 基于轨迹与路面重心偏离度误差的预测自动差速小车循迹控制策略 三 轨迹图像的处理要点 四 本篇部分核心控制策略python代码 五 结论 一 前言 基于最近的测试 得到了一种粗略控制的算法 其控制效果适合单线路和急转弯的情
  • DevExpress控件手册

    https www evget com article 2018 7 17 28180 html 手册是全英文的 有chm和pdf两种格式 winform手册有两百来兆 内容的确是很详细了 每个控件还有入门的详细例子 建议下载CHM格式的
  • 【AUTOSAR】CCP协议的代码分析与解读(二)----CCP协议格式和命令代码

    CCP协议介绍 CCP的全称是CAN Calibration Protocol CAN标定协议 是基于CAN总线的ECU标定协议规范 CCP协议遵从CAN2 0通信规范 支持11位标准与29位扩展标识符 CCP通信方式 CCP协议采用主从通
  • 单链表的增删改查

    链表的增 改 查 删 public class LinkLIST int size 节点个数 NewNode head 头节点地址 class NewNode int val 存放具体数据 NewNode next 存下一个节点的地址 pu
  • python全排列库_python——全排列数的生成方式

    问题描述 输入整数N 1 lt N lt 10 生成从1 N所有整数的全排列 输入形式 输入整数N 输出形式 输出有N 行 每行都是从1 N所有整数的一个全排列 各整数之间以空格分隔 各行上的全排列不重复 输出各行遵循 小数优先 原则 在各
  • 基于STM32、OV2640及ESP8266的无线图传

    一 简介 本文利用STM32F407单片机 OV2640摄像机模块以及ESP8266 WIFI模块 并基于C 编写的TCP上位机服务 来实现图像的无线传输 本文受启发于博客 ESP8266 STM32F407 OV7670实现图片传输 在此
  • python3安装pyhanlp (中文自然语言处理的工具包) 超详细。

    第一步 首先要有个python的环境 还得有个java的环境 安装jdk8以上 并配置好环境变量 自己想办法 第二步 下载jpype的安装包 下载完成后切换到下载路径 直接用pip装 pip3 install JPype1 0 6 3 cp
  • 外观(Facade)模式

    什么是 Facade 模式 Facade 外观 模式为子系统中的各类 或结构与方法 提供一个简明一致的界面 隐藏子系统的复杂性 使子系统更加容易使用 出自百度文库 即当子系统复杂或者繁锁时 我们让子系统提供一个窗口 程序中称为接口 其它程序
  • BeanFactory和FactoryBean的区别

    区别 https liayun blog csdn net article details 110391066 BeanFactory是个Factory 也就是IOC容器或对象工厂 而FactoryBean就是个Bean 在Spring中