实例区别BeanFactory和FactoryBean

2024-01-10 10:08

本文主要是介绍实例区别BeanFactory和FactoryBean,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

从代码角度写了一个帖子去解释BeanFactory和FactoryBean,感概下Mybatis对Spring框架用的炉火纯青的水平。更多Spring内容进入【Spring解读系列目录】。

BeanFactory

什么是BeanFactory?看名字也能明白这是一个工厂,其实是Spring框架中的一个顶层类。是Spring提供的一个工厂,能够产生注册在Spring中的对象。比如BeanFactory.getBean(),就可以拿到一个bean的实例对象。或者实例化AnnotationConfigApplicationContext类就可以拿到其对象,也就是说BeanFactory是为了产生对象使用的。这个其实没什么好讲的,重点就在于FactoryBean

BeanFactory bean=new AnnotationConfigApplicationContext();
bean.getBean("service");

FactoryBean

FactoryBean是Spring中的一个特殊的bean。什么是bean呢?其实只要一个类交给Spring容器管理就可以称作一个Bean,也可以直接说就是一个对象。那FactoryBean有什么特殊性呢?那就是FactoryBean可以构造一个新的bean出来。我们先用一个例子来简单说下,先创建一个测试类TestDaoFactoryBean,然后创建一个MyDaoFactroyBean类实现FactoryBean,再实现里面的方法,起个名字叫factoryBeanTest

public class TestDaoFactoryBean { }
@Component("factoryBeanTest")
public class MyFactroyBean implements FactoryBean {@Overridepublic Object getObject() throws Exception {return new TestDaoFactoryBean(); //getObject返回新构建的类}@Overridepublic Class<?> getObjectType() {return TestDaoFactoryBean.class;}@Overridepublic boolean isSingleton() {  //设置单例模式return true;}
}

构建完成以后我们就尝试去把MyFactroyBean拿出来,所以我们用一个Test类取一下:

public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext anno=new AnnotationConfigApplicationContext(AppConfig.class);System.out.println(anno.getBean("factoryBeanTest"));}
}
打印结果:
com.demo.dao.TestDaoFactoryBean@701fc37a

最终运行的结果发现取出来的并不是MyFactroyBean,而是我们在getObject()这个方法里返回的对象。那么怎么拿到MyFactroyBean呢,只要把名字前面加一个”&”符号就可以了

System.out.println(anno.getBean("&factoryBeanTest"));
打印结果:
com.demo.dao.MyFactroyBean@701fc37a

为什么会这样呢?先不解释,不过根据这个现象我们总结一下:
如果一个类实现了FactoryBean,那么Spring容器中就会生成两个对象,一个是getObject()方法返回的对象,还有一个是当前的对象(也就是this本身)。getObject()对象存的是指定的对象,在Bean上指定名字的对象。当前对象是存的是”&”+当前类的名字

FactoryBean的作用

要想解释为什么Spring要这样设计,首先我们看先看FactoryBean有什么具体的作用。做一个假设,我们需要引用第三方的一个jar包,这里面有一个配置类A,而这个配置类A又依赖了其他100个类。那么请问,这个其他的100个类的依赖,应该由谁去管理呢?不管由谁管理,一定不是让使用者管理对不对,我们期望的是在Spring中配置了一个A的bean,就可以正常使用这个jar包了,而不是说要使用者把A中所有的依赖都维护一遍,这显然不合理。比如我们经常使用的Mybatis就是一个非常经典的例子。

一般来说都会把Mybatis交给Spring管理,如果Mybatis里面使用的第三方的类也都需要开发人员去维护是不是极为不合理。所以我们期望就是Mybatis自己维护好自己的关系,然后提供一个bean(对象)出来,我只要维护这个bean就可以完成Spring的管理了。以Mybatis中的SqlSessionFactory为例。如果要我们自己配Spring依赖关系,首先要配一个SqlSessionFactorybean,然后发现里面依赖了Configuration对象,又要配置一堆依赖关系,配完以后Configuration对象又依赖了Environment对象和好几十个其他对象,要一个一个配bean出来,单单交给Spring管理那就是一个相当巨大的工程了,还不如自己写来的简单。所以最好的办法就是Mybatis自己把这一切的关系都维护好了,使用者只要引用SqlSessionFactory一个bean就搞定了,这个时候FactoryBean就有大作用了。Mybatis也提供了这样一个bean叫做SqlSessionFactoryBean就做了这样一个事情。

#Mybatis提供的FactorBean:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {...private SqlSessionFactory sqlSessionFactory;...@Overridepublic SqlSessionFactory getObject() throws Exception {if (this.sqlSessionFactory == null) {afterPropertiesSet();}return this.sqlSessionFactory;}...
}

这个类也实现了FactoryBean,虽然叫做SqlSessionFactoryBean但是它最终返回的是SqlSessionFactory。在SqlSessionFactoryBean中Mybatis就把ConfigurationEnvironment等等这些对象提前初始化,并且用setter方法赋值,那么最终我们拿到的bean就是已经初始化好了对象直接可以用。

FactoryBean使用范例

所以为了加深理解,我们也可以做一个例子,首先我们改造一下TestDaoFactoryBean让其具备一些属性。

public class TestDaoFactoryBean {private String a1;private Integer a2;public String getA1() {return a1;}public void setA1(String a1) {this.a1 = a1;}public Integer getA2() {return a2;}public void setA2(Integer a2) {this.a2 = a2;}
}

然后修改MyFactroyBean,并且在里面初始化TestDaoFactoryBean

@Component("factoryBeanTest")
public class MyFactroyBean implements FactoryBean {@Overridepublic Object getObject() throws Exception {TestDaoFactoryBean factoryBean=new TestDaoFactoryBean();factoryBean.setA1("a1");factoryBean.setA2(22222);return factoryBean;}@Overridepublic Class<?> getObjectType() {return TestDaoFactoryBean.class;}@Overridepublic boolean isSingleton() {return true;}
}

最后获取一下,这样我们就完成了TestDaoFactoryBean的初始化赋值,外部如果要使用就会发现其中的属性a1a2已经被构建过了。

public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext anno=new AnnotationConfigApplicationContext(AppConfig.class);TestDaoFactoryBean factoryBean= (TestDaoFactoryBean) anno.getBean("factoryBeanTest");System.out.println("getA1:"+factoryBean.getA1());System.out.println("getA2:"+factoryBean.getA2());}
}
打印结果:
getA1:a1
getA2:22222

但是要注意,实现了FactoryBean的本身是和别的bean没有区别的,唯一的区别就是返回的对象要指定,因此这些实现了FactoryBeanbean也可以进行业务实现。当然这点要根据具体的业务具体去分析。

总结

举个不恰当的例子BeanFactory是个鞋厂,FactoryBean就是一个特殊的鞋子,这个鞋子能够根据需求产生新的鞋子,这么牛逼的鞋子,就问你服不服。从名字上看BeanFactorybean工厂只能生产bean。而FactoryBean是一个bean (对象),但是这个bean能够生产新的bean。好绕,大家理解下。

那么如果有人问道这两个的区别,大概可以这样说:BeanFactory是Spring容器当中的工厂,它能生产我们交给Spring的类,并且获取这些类的对象。FactoryBean只是Spring中的一个特殊的bean接口,FactoryBean需要被实现三个方法,实现以后可以返回一个新的bean,这个新的bean就是getObject()返回出去的对象。并且存在的形式也不同,得到FactoryBean本身需要用&+类名,而要得到FactoryBean产生的对象则要使用真实指定的bean名字。

这篇关于实例区别BeanFactory和FactoryBean的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/590430

相关文章

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

go 指针接收者和值接收者的区别小结

《go指针接收者和值接收者的区别小结》在Go语言中,值接收者和指针接收者是方法定义中的两种接收者类型,本文主要介绍了go指针接收者和值接收者的区别小结,文中通过示例代码介绍的非常详细,需要的朋友们下... 目录go 指针接收者和值接收者的区别易错点辨析go 指针接收者和值接收者的区别指针接收者和值接收者的

售价599元起! 华为路由器X1/Pro发布 配置与区别一览

《售价599元起!华为路由器X1/Pro发布配置与区别一览》华为路由器X1/Pro发布,有朋友留言问华为路由X1和X1Pro怎么选择,关于这个问题,本期图文将对这二款路由器做了期参数对比,大家看... 华为路由 X1 系列已经正式发布并开启预售,将在 4 月 25 日 10:08 正式开售,两款产品分别为华

SQL表间关联查询实例详解

《SQL表间关联查询实例详解》本文主要讲解SQL语句中常用的表间关联查询方式,包括:左连接(leftjoin)、右连接(rightjoin)、全连接(fulljoin)、内连接(innerjoin)、... 目录简介样例准备左外连接右外连接全外连接内连接交叉连接自然连接简介本文主要讲解SQL语句中常用的表

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

CSS Padding 和 Margin 区别全解析

《CSSPadding和Margin区别全解析》CSS中的padding和margin是两个非常基础且重要的属性,它们用于控制元素周围的空白区域,本文将详细介绍padding和... 目录css Padding 和 Margin 全解析1. Padding: 内边距2. Margin: 外边距3. Padd

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处