Spring中BeanFactory与FactoryBean的区别
在Spring中有BeanFactory和FactoryBean这2个接口,从名字来看很相似,比较容易搞混。
一、BeanFactory
BeanFactory
是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean()
、containsBean()
等管理Bean的通用方法。Spring的容器都是它的具体实现如:
- DefaultListableBeanFactory
- XmlBeanFactory
- ApplicationContext
这些实现类又从不同的维度分别有不同的扩展。
1.1 BenaFactory源码
public interface BeanFactory { /**
* 用来获得实例的引用,并且区分FactoryBean区分。
* 如果使用bean的名字myJndiObject获取FactoryBean,返回的是一个工厂,而不是工厂的实例;如果需要获得工厂实例,需要转义。
*/
String FACTORY_BEAN_PREFIX = "&"; /**
* 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.
*/
Object getBean(String name) throws BeansException; /**
* 根据bean的名称,获取指定的bean实例,该实例可以是共享的,也可以是独立的.并且增加了一个类型的检验。
*/
<T> T getBean(String name, Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; /**
* 根据给定类型返回匹配的bean实例.
*/
<T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; /**
* 检查spring的bean容器中是否包含有该bean
*/
boolean containsBean(String name); /**
* 判断bean的作用域是否是singleton
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException; /**
* 判断bena的作用域是否是prototype
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException; /**
* 检查给定名称的bean是否和指定类型匹配.更确却的说是通过检查给定的bean,返回指定类型的目标对象
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; /**
* 获取给定名称的bean的class类型
*/
Class<?> getType(String name) throws NoSuchBeanDefinitionException; /**
* 获取给定bean名称的别名,如果根据别名检索,将会获得原始bean名称。
*
String[] getAliases(String name); }
1.2 使用场景
- 从Ioc容器中获取Bean(byName or byType):context.getBean("father", Father.class)、context.getBean("father")
- 检索Ioc容器中是否包含指定的Bean: context.containsBean("father")
- 判断Bean是否为单例: context.isSingleton("father")
二、FactoryBean
首先它是一个Bean,但又不仅仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何Bean的实例。
2.1 FactoryBean源码
public interface FactoryBean<T> { /**
* 从工厂中获取bean实例
*/
T getObject() throws Exception; /**
* 从工厂中获取bean实例对象的类型
*/
Class<?> getObjectType(); /**
* 工厂创建的对象是否是单例
*/
boolean isSingleton(); }
从它定义的接口可以看出,FactoryBean
表现的是一个工厂的职责。 即一个Bean A如果实现了FactoryBean接口,那么A就变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()
返回的对象,而不是A本身,如果要获取工厂A自身的实例,那么需要在名称前面加上'&
'符号。
- getObject('name')返回工厂中的实例
- getObject('&name')返回工厂本身的实例
通常情况下,bean 无须自己实现工厂模式,Spring 容器担任了工厂的 角色;但少数情况下,容器中的 bean 本身就是工厂,作用是产生其他 bean 实例。由工厂 bean 产生的其他 bean 实例,不再由 Spring 容器产生,因此与普通 bean 的配置不同,不再需要提供 class 元素。
2.2 示例
先定义一个Bean实现FactoryBean接口:
@Component
public class MyBean implements FactoryBean {
private String message;
public MyBean() {
this.message = "通过构造方法初始化实例";
} public MyBean(String message) {
this.message = message;
} @Override
public Object getObject() throws Exception {
// 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例
return new MyBean("通过FactoryBean.getObject()创建实例");
}
@Override
public Class<?> getObjectType() {
return MyBean.class;
}
public String getMessage() {
return message;
} @Override
public boolean isSingleton() {
return false;
}
}
MyBean实现了FactoryBean接口的三个方法,getObject()是可以返回任何对象的实例的,这里测试就返回MyBean自身实例,且返回前给message字段赋值。同时在构造方法中也为message赋值。然后测试代码中先通过名称获取Bean实例,打印message的内容,再通过&+名称
获取实例并打印message内容。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = HelloApplication.class)
public class FactoryBeanTest {
@Autowired
private ApplicationContext context;
@Test
public void test() {
MyBean myBean1 = (MyBean) context.getBean("myBean");//返回工厂中的实例,调用FactoryBean.getObject()创建实例
System.out.println("myBean1 = " + myBean1.getMessage());
MyBean myBean2 = (MyBean) context.getBean("&myBean");//返回工厂本身,通过构造方法初始化实例
System.out.println("myBean2 = " + myBean2.getMessage());
System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
}
}
打印结果:
myBean1 = 通过FactoryBean.getObject()创建实例
myBean2 = 通过构造方法初始化实例
myBean1.equals(myBean2) = false
2.3 使用场景
说了这么多,为什么要有FactoryBean
这个东西呢,有什么具体的作用吗?
FactoryBean在Spring中最为典型的一个应用就是用来创建AOP的代理对象。
我们知道AOP实际上是Spring在运行时创建了一个代理对象,也就是说这个对象,是我们在运行时创建的,而不是一开始就定义好的,这很符合工厂方法模式。更形象地说,AOP代理对象通过Java的反射机制,在运行时创建了一个代理对象,在代理对象的目标方法中根据业务要求织入了相应的方法。这个对象在Spring中就是——ProxyFactoryBean
。
所以,FactoryBean为我们实例化Bean提供了一个更为灵活的方式,我们可以通过FactoryBean创建出更为复杂的Bean实例。
三、区别
- 他们两个都是个工厂,但
FactoryBean
本质上还是一个Bean,也归BeanFactory
管理 BeanFactory
是Spring容器的顶层接口,FactoryBean
更类似于用户自定义的工厂接口。
参考: Spring中BeanFactory与FactoryBean的区别
Spring中BeanFactory与FactoryBean的区别的更多相关文章
- 【Java面试】Spring中 BeanFactory和FactoryBean的区别
一个工作了六年多的粉丝,胸有成竹的去京东面试. 然后被Spring里面的一个问题卡住,唉,我和他说,6年啦,Spring都没搞明白? 那怎么去让面试官给你通过呢? 这个问题是: Spring中Bean ...
- spring中BeanFactory和FactoryBean的区别
共同点: 都是接口 区别: BeanFactory 以Factory结尾,表示它是一个工厂类,用于管理Bean的一个工厂 在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器 ...
- Spring中BeanFactory与FactoryBean到底有什么区别?
一.BeanFactory BeanFactory是一个接口,它是Spring中工厂的顶层规范,是SpringIoc容器的核心接口,它定义了getBean().containsBean()等管理Bea ...
- Spring中BeanFactory与ApplicationContext的区别
BeanFactory:Bean工厂接口,是访问Spring Bean容器的根接口,基本Bean视图客户端.从其名称上即可看出其功能,即实现Spring Bean容器的读取. ApplicationC ...
- Spring中BeanFactory和ApplicationContext的区别
1. BeanFactory负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的生命周期. 2. ApplicationContext除了提供上述BeanF ...
- BeanFactory 和FactoryBean的区别
转自:https://www.cnblogs.com/aspirant/p/9082858.html BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是 ...
- Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法
Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法 1. BeanFactory BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于 ...
- BeanFactory和FactoryBean的区别
转自:http://blog.csdn.net/wangbiao007/article/details/53183764 1.BeanFactory BeanFactory是IOC最基本的容器,负责生 ...
- 转:BeanFactory和FactoryBean的区别
一.BeanFactory简介 BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是一种典型的BeanFactory.原始的BeanFactory无法支持 ...
随机推荐
- springboot(1)@SpringBootApplication
首先来看下Spring Boot项目中的运行类,基本上每个项目都会有该启动类: @SpringBootApplication public class Application { public sta ...
- 微信小程序:用 Promise 解决方案代替回调地狱。 修复 this._invokeMethod is not a function 的问题
/** * 将回调地狱转换为 Promise 形式 * https://blog.csdn.net/SEAYEHIN/article/details/88663740 * raw: wx.downlo ...
- sumdoc t3 final dir.txt
C:\Users\zhoufeiyue\Documents\sumdoc t3 final\sumdoc t3 final dir.txtC:\Users\zhoufeiyue\Documents\s ...
- kotlin基础 枚举
enum class WEEK {星期一,星期二,星期三,星期四,星期五,星期六,星期日} Kotlin 枚举类 枚举类最基本的用法是实现一个类型安全的枚举. 枚举常量用逗号分隔,每个枚举常量都是一个 ...
- CobaltStrike3.14破解
原文发布在:https://bithack.io/forum/310 8月6日已更新 之前发的是5月2号破解的,并且官方作者的exit暗桩没有去掉.看到很多人用此版本遇到问题,抽空修复了下bug.此版 ...
- 路径规划: PRM 路径规划算法 (Probabilistic Roadmaps 随机路标图)
随机路标图-Probabilistic Roadmaps (路径规划算法) 路径规划作为机器人完成各种任务的基础,一直是研究的热点.研究人员提出了许多规划方法如: 1. A* 2. Djstar 3. ...
- 经典面试题之——如何自由转换两个没有继承关系的字段及类型相同的实体模型,AutoMapper?
相信很多童鞋们都被问到过这个问题,不管是在面试的时候被问过,还是笔试题里考过,甚至有些童鞋们找我要学习资料的时候我也考过这个问题,包括博主我自己,也曾被问过,而且博主现在有时作为公司的面试官,也喜欢问 ...
- Vue 搭建项目
Vue 搭建项目 一.node下载安装: 1.下载:https://nodejs.org/en/download/ 2.安装默认许选择,下一步就行: 3.安装完之后就可以使用npm命令 二.通过@v ...
- Modelsim SE-64 10.4的安装 、破解以及远程使用
1.准备好modelsim SE-64 10.4的安装包和破解文件(modelsim-win64-10.4-se.exe 和MentorKG.exe ,patch_dll.bat). 2.安装 好 ...
- Ant Design 学习记录
遇到的问题: 点击列表中的一个字段 , 显示出一条指定id(其他筛选条件的)数据 解决这个问题之前,要先了解 Antd的 Table中的 Column 列描述数据对象,是 columns 中的一项 ...