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无法支持 ...
随机推荐
- win10安装ubuntu双系统遇到的问题
安装过程学习了几个博客 Ubuntu 16.04与Win10双系统双硬盘安装图解:https://www.cnblogs.com/coxiseed/p/9945202.html?tdsourcetag ...
- docker port is already allocated 的解决方案
ps -aux | grep -v grep | grep docker-proxy 第二列为进程号 停止 doker 进程,删除所有容器,然后删除 local-kv.db 这个文件,再启动 dock ...
- odoo开发笔记 -- 当前时间&时间运算相关
当前日期/时间: from datetime import datetime, timedelta now_time = datetime.now() today_date_format = now_ ...
- 工具推荐--Mac下画图软件:Omnigraffle
场景描述: 日常工作中,开发的小伙伴可能会遇到,需要画流程图,架构图,时序图,UML图,网络拓扑图...等等各种图,有的小伙伴用Visio,ProcessOn,亿图图示......又是一堆软件,先不说 ...
- jstl标签库使用报错index_jsp.java找不到问题
初学jstl的时候记得只需要讲jstl和standard的jar放在lib下面,然后jsp中使用对应导入语法就可以使用标签库了. 但那时候用的是myeclipes,myeclipes的导包的过程记得是 ...
- scrapy中的middleware
反反爬虫相关机制 Some websites implement certain measures to prevent bots from crawling them, with varying d ...
- linux安装redis时报collect2: fatal error: cannot find 'ld'和In file included from adlist.c:34:0:
如题,看了下该ld命令所在文件: [root@centos redis-]# whereis ld ld: /usr/bin/ld.gold /usr/bin/ld /usr/bin/ld.bfd / ...
- 为什么java里面经常作List判断的时候,既要判断list不为null,又要判断size>0呢?
没有考虑到具体的问题上面,我们单纯的来讲: 为什么java里面经常作List判断的时候,既要判断list不为null,又要判断size>0呢? list == null 说明list没有初始化( ...
- a simple machine learning system demo, for ML study.
Machine Learning System introduction This project is a full stack Django/React/Redux app that uses t ...
- TensorFlow 8 bit模型量化
本文基本参考自这篇文章:8-Bit Quantization and TensorFlow Lite: Speeding up mobile inference with low precision ...