实例区别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

相关文章

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

结构体和联合体的区别及说明

《结构体和联合体的区别及说明》文章主要介绍了C语言中的结构体和联合体,结构体是一种自定义的复合数据类型,可以包含多个成员,每个成员可以是不同的数据类型,联合体是一种特殊的数据结构,可以在内存中共享同一... 目录结构体和联合体的区别1. 结构体(Struct)2. 联合体(Union)3. 联合体与结构体的

什么是 Ubuntu LTS?Ubuntu LTS和普通版本区别对比

《什么是UbuntuLTS?UbuntuLTS和普通版本区别对比》UbuntuLTS是Ubuntu操作系统的一个特殊版本,旨在提供更长时间的支持和稳定性,与常规的Ubuntu版本相比,LTS版... 如果你正打算安装 Ubuntu 系统,可能会被「LTS 版本」和「普通版本」给搞得一头雾水吧?尤其是对于刚入

MySQL的索引失效的原因实例及解决方案

《MySQL的索引失效的原因实例及解决方案》这篇文章主要讨论了MySQL索引失效的常见原因及其解决方案,它涵盖了数据类型不匹配、隐式转换、函数或表达式、范围查询、LIKE查询、OR条件、全表扫描、索引... 目录1. 数据类型不匹配2. 隐式转换3. 函数或表达式4. 范围查询之后的列5. like 查询6

python中json.dumps和json.dump区别

《python中json.dumps和json.dump区别》json.dumps将Python对象序列化为JSON字符串,json.dump直接将Python对象序列化写入文件,本文就来介绍一下两个... 目录1、json.dumps和json.dump的区别2、使用 json.dumps() 然后写入文

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

native和static native区别

本文基于Hello JNI  如有疑惑,请看之前几篇文章。 native 与 static native java中 public native String helloJni();public native static String helloJniStatic();1212 JNI中 JNIEXPORT jstring JNICALL Java_com_test_g

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |