简单了解Spring中BeanFactory与FactoryBean的区别
作者:何其有静 发布时间:2022-01-14 03:59:20
这篇文章主要介绍了简单了解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更类似于用户自定义的工厂接口。
来源:https://www.cnblogs.com/heqiyoujing/p/12077573.html
猜你喜欢
- 一、 搭建struts2环境在myeclipse下,右击项目->MyEclipse->Project Facets->in
- 报错翻译: compileSdkVersion android-24”需要JDK 1.8或更高版本编译。报错现象如下图:原因:st
- 介绍: Mybatis-Plus(简称MP)
- 前言本文学习MP中的更新操作方法,带大家一起查看源码,了解更新操作的方法。学会熟练地去运用更新方法解决自己在项目中的问题。一、通过id更新1
- 如今,企业级应用程序的常见场景是同时支持HTTP和HTTPS两种协议,这篇文章考虑如何让Spring Boot应用程序同时支持HTTP和HT
- 本文主要介绍我为桌面和 Web 设计的一个超级秘密 Flutter 项目使用了画布和可拖动节点界面。本教程将展示我如何使用堆栈来使用小部件完
- File类File类事java.io包中唯一代表磁盘文件本身的对象。File类定义了一些与平台无关的方法来操作文件,可以通过调用File类中
- 1.简介学了几周的Java,闲来无事,写个乞丐版的扫雷,加强一下Java基础知识。2.编写过程编写这个游戏,一共经历了三个阶段,编写了三个版
- static修饰符是java里面非常常用的一个东西,用法也非常多。然而,在kotlin里竟然没有这个东西!那该如何替代呢?本文就总结了下ja
- 为什么要使用路由在之前我们的代码中,页面跳转使用的代码如下所示:Navigator.of(context).push( Mate
- 本文实例为大家分享了android自定义环形对比图的具体代码,供大家参考,具体内容如下1.首先在res/values里创建一个attr.xm
- 加载资源文件比较常用的有两种:一、用ClassLoader,说到这里就不得不提一下ClassLoader的分类,java内置的ClassLo
- 数据库结构如下strategy中有外键member_id(关联member表)外键strategy_category(关联category表
- 本文为大家分享了Android实现带动画效果的可点击展开TextView 制作代码,效果图: 收起(默认)效果:点击展开后的效果:源码: 布
- fastjson转换对象实体@JsonProperty不生效项目场景请求第三方应用 返回json数据问题描述第三方返回的数据中,存在java
- 项目结构项目路径可以自己定义,只要路径映射正确就可以pom.xml <properties> <spring.versio
- 前言:封装、继承和多态是面向对象编程的三大特征。1.封装1.1.封装概念封装就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据
- 一、选择结构大纲if单选择结构if双选择结构if多选择结构嵌套的if结构switch多选择结构二、if单选择结构我们很多时候需要去判断一个东
- 1.设置url-pattern为*.do(最为常见的方式)只要你的请求url中包含配置的url-pattern,该url就可以到达Dispa
- 前言Future的问题写多线程程序的时候,可以使用Future从一个异步线程中拿到结果,但是如果使用过程中会发现一些问题:如果想要对Futu