当前位置: 首页 > news >正文

Springboot扩展点之FactoryBean

前言

FactoryBean是一个有意思,且非常重要的扩展点,之所以说是有意思,是因为它老是被拿来与另一个名字比较类似的BeanFactory来比较,特别是在面试当中,动不动就问你:你了解Beanfactory和FactoryBean的区别吗?其实两个是完全不同的接口,如果非要说出有什么明显区别,大概就是名字吧。为什么又说非常重要呢?那是因为在创建一些比较复杂的bean的时候,常规的方式不能使用,就可以考虑使用FactoryBean,特别其他框架技术与Spring集成的时候,如mybatis与Spring的集成,大家都知道,mybatis是通过SqlSessionFactory创建出Sqlsession来执行sql的,那么Service层在调用Dao层的接口来执行数据库操作时肯定得持有SqlSessionFactory,那么问题来了:Spring容器怎么才能持有SqlSessionFactory呢?答案就是SqlSessionFactoryBean,它实现了FactoryBean接口。

既然FactoryBean如此神奇,那么就先盘一盘它的主要功能特性,然后再通过一个示例来验证一下,最后再深入盘一盘其工作原理 。

功能特性

1、FactoryBean接口有三个方法:1、getObject(),用于获取bean,主要应用在创建一些复杂的bean的场景;2、getObjectType(),用于获取返回bean的类型;3、isSingleton(),用于判断返回bean是否属于单例,默认trure,通俗说就是工厂bean;

2、BeanFactory是Spring bean容器的根接口,ApplicationContext是Spring bean容器的高级接口,继承于BeanFactory,通俗理解就是生成bean的工厂;

所以FactoryBean与BeanFactory本质上是完全不同的两个接口。既然完全不同,又说什么区别呢?至少我是这么认为的。

实现方式

那么FactoryBean怎么用呢?这里先举一个场景:假如需要要创建一个特别复杂的类Computer

1、定义Computer类;

@Slf4j
public class Computer {private String type;public String getType() {return type;}public void setType(String type) {this.type = type;}public Computer() {log.info("----Computer类无参数构造方法触发执行");}public Computer(String type) {this.type = type;log.info("----Computer类有参数构造方法触发执行");}
}

2、定义ComputerFactoryBean,实现FactoryBean接口,实现了getObject(),创建了一个“复杂”的Bean;在getObjectType()返回了Bean的类型;在isSingleton()指定Bean的作用域为单例;

@Component
@Slf4j
public class ComputerFactoryBean implements FactoryBean {private String name = "ComputerFactoryBean本尊";public ComputerFactoryBean() {log.info("----ComputerFactoryBean无参数构造方法触发执行");}@Overridepublic Object getObject() throws Exception {log.info("----com.fanfu.bean.ComputerFactoryBean.getObject()触发执行-start");Computer computer = new Computer("商用笔记本电脑");log.info("----com.fanfu.bean.ComputerFactoryBean.getObject()触发执行-end");return computer;}@Overridepublic Class<?> getObjectType() {return Computer.class;}@Overridepublic boolean isSingleton() {return true;}
}

3、编写单元测试,从Spring容器中取出beanName为"computeFactoryBean"的bean,通常情况下,如果ComputerFactoryBean未实现FactoryBean接口,getBean("computeFactoryBean")的结果是computeFactoryBean对象;而实现了FactoryBean接口,getBean("computeFactoryBean")的结果的是getObject()方法中返回的结果,即computer,这就是FactoryBean如此神奇的地方。

@Test
public void test6() {log.info("----单元测试执行开始");log.info("----Spring容器实例化开始");AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");log.info("----Spring容器实例化完成");ComputerFactoryBean computerFactoryBean = ((ComputerFactoryBean) context.getBean("&computerFactoryBean"));Computer computer = (Computer) context.getBean("computerFactoryBean");Assert.isTrue(computerFactoryBean.getClass().getName().equals("com.fanfu.bean.ComputerFactoryBean"));Assert.isTrue(computer.getClass().getName().equals("com.fanfu.entity.Computer"));log.info("----单元测试执行完毕");
}

单元测试结果:

工作原理

从单元测试验证结果来看,ComputerFactoryBean本尊在Spring容器实例化的过程中,就以非懒加载的单例bean实例化完成注册到了Spring容器里。顺着context.getBean("computerFactoryBean")往下跟踪,会发现接着调用了AbstractApplicationContext#getBean(java.lang.String)-->AbstractBeanFactory#getBean(java.lang.String)-->AbstractAutowireCapableBeanFactory#getObjectForBeanInstance()-->AbstractBeanFactory#getObjectForBeanInstance(),到这是一个关键点:

1、AbstractBeanFactory#getObjectForBeanInstance()中判断是否bean是否是一个工厂引用,即beanName是否是“&”开头,如果beanName是以“&”开头,则直接返回本尊;如果不是,则继续向下执行;

2、检查bean是否实现了FactoryBean接口,如果获取的bean没有实现FactoryBean接口,则直接返回;如果获取的bean实现了FactoryBean接口,则继续向下执行;

3、对获取的bean强制转换为FactoryBean,然后去执行FactoryBean接口实现类的getObject();

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {//检查bean是否是一个工厂引用,即beanName是否是“&”开头if (BeanFactoryUtils.isFactoryDereference(name)) {if (beanInstance instanceof NullBean) {return beanInstance;}if (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());}if (mbd != null) {mbd.isFactoryBean = true;}//如果beanName是以“&”开头,则直接返回本尊return beanInstance;}//如果获取的bean没有实现FactoryBean接口,则直接返回;if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}Object object = null;if (mbd != null) {mbd.isFactoryBean = true;}else {object = getCachedObjectForFactoryBean(beanName);}if (object == null) {// 如果获取的bean实现FactoryBean接口,则对bean进行强制转换FactoryBean<?> factory = (FactoryBean<?>) beanInstance;if (mbd == null && containsBeanDefinition(beanName)) {mbd = getMergedLocalBeanDefinition(beanName);}boolean synthetic = (mbd != null && mbd.isSynthetic());//去执行FactoryBean接口实现类的getObject()object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;
}

总结

总体来讲,从FactoryBean的实现方式到工作原理,都很简单,同时也是有大用处的扩展点,特别要必要牢牢掌握。当然,如果有面试官再问你,FactoryBean与BeanFactory有什么区别的时候?不要再犹豫,直接告诉他:”FactoryBean与BeanFactory本身并没有什么区别,但是我可以分别给你介绍介绍这两个接口有什么用处。FactoryBean是一个工厂Bean,在需要创建比较复杂的bean的时候可以用到,BeanFactory是Spring bean容器的根接口,也就是说实现BeanFactory,可以得到一个最基础的Spring容器,Spring中的所有高级容器都继承了这个根接口。“

如果你能这样回答这个问题,相信会给面试官留下一下好印象的。

相关文章:

Springboot扩展点之FactoryBean

前言FactoryBean是一个有意思&#xff0c;且非常重要的扩展点&#xff0c;之所以说是有意思&#xff0c;是因为它老是被拿来与另一个名字比较类似的BeanFactory来比较&#xff0c;特别是在面试当中&#xff0c;动不动就问你&#xff1a;你了解Beanfactory和FactoryBean的区别吗…...

新库上线 | CnOpenDataA股上市公司交易所监管措施数据

A股上市公司交易所监管措施数据 一、数据简介 证券市场监管是指证券管理机关运用法律的、经济的以及必要的行政手段&#xff0c;对证券的募集、发行、交易等行为以及证券投资中介机构的行为进行监督与管理。 我国《证券交易所管理办法》第十二条规定&#xff0c;证券交易所应当…...

同步辐射XAFS表征方法的应用场景分析

X射线吸收精细结构XAFS表征方法是一种用于研究物质结构和化学环境的分析技术。XAFS 使用 X 射线照射到物质表面&#xff0c;并观察由此产生的 X 光吸收谱。 ​XAFS 技术通常应用于研究高分子物质、生物分子、纳米结构和其他类型的物质。例如&#xff0c;XAFS 可以用来研究高分子…...

06 antdesign react Anchor 不同页面之间实现锚点

react Anchor 不同页面之间实现锚点一、定义二、使用步骤三、开发流程(一)、组件(二)、页面布局(三)、点击事件(四)、总结说明一、react单页面应用&#xff0c;当前页面的锚点二、react单页面应用&#xff0c;不同页面的锚点思路&#xff1a;锚点只能在当前页面使用&#xff0c…...

mysql调优-内存缓冲池

因本地查询和服务器查询相比服务器慢了很多&#xff0c;同样的数据&#xff0c;同样的sql查询&#xff0c;考虑了是不是链接太多了&#xff0c;自行查询了下&#xff0c;我使用的c3p0的链接池&#xff0c;配置一个小时超时&#xff0c;正常情况下是20多个链接&#xff0c;而mys…...

【LeetCode】每日一题(5)

目录 题目&#xff1a;2341. 数组能形成多少数对 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;2341. 数组能形成多少数对 -…...

输入任意多个整数, 把这些数据保存到文件data.txt中.(按ctrl + z)

#pragma once #include <iostream> #include <fstream> using namespace std; /* 输入任意多个整数, 把这些数据保存到文件data.txt中. 如果在输入的过程中, 输入错误, 则提示用户重新输入. 指导用户输入结束(按ctrl z) [每行最多保存10个整数] */ int main() { …...

Mysql数据库的时间(3)一如何用函数插入时间

暂时用下面四个日期函数插入时间 如:insert into Stu(time) values (now()); Mysql的时间函数描述对应的Mysql的时间类型now()/sysdate()NOW()函数以YYYY-MM-DD HH:MM:SS返回当前的日期时间date/time/dateTime/timeStamp/yearcurDate()/current_date()返回当前的日期YYYY-M…...

关于eval函数(将JSON格式的字符串转换成JSON格式对象)

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>关于eval函数</title> </head> <body> <!--JSON是一种行业内的数据交换格式标准。在JS当中以对象的形式存在…...

2023最强软件测试面试题,精选100 道,内附答案版,冲刺金3银4

精挑细选&#xff0c;整理了100道软件测试面试题&#xff0c;都是非常常见的面试题&#xff0c;篇幅较长&#xff0c;所以只放出了题目&#xff0c;答案在评论区&#xff01; 测试技术面试题 1、什么是兼容性测试&#xff1f;兼容性测试侧重哪些方面&#xff1f; 2、我现在有…...

一文搞懂Docker容器里进程的 pid 是如何申请出来的?

如果大家有过在容器中执行 ps 命令的经验&#xff0c;都会知道在容器中的进程的 pid 一般是比较小的。例如下面我的这个例子。 # ps -ef PID USER TIME COMMAND1 root 0:00 ./demo-ie13 root 0:00 /bin/bash21 root 0:00 ps -ef 不知道大家是否和我一样…...

若依框架如何新增自定义主题风格

若依框架新增主题风格1.实现结果2.实现步骤2.1Settings目录下2.2 variables.scss2.3 sidebar.scss2.4 Logo.vue2.5 Siderbar目录下的index.vue1.实现结果 2.实现步骤 需要改动的文件目录&#xff1a; 2.1Settings目录下 <div class"setting-drawer-block-checbox-it…...

C语言格式化输入和输出; Format格式化

Format格式化 %1s或者%2s,%3s:取字符串的前1,2或者3位。%*c:屏蔽一个字符。%[A-Z]:取一个A到Z的值。 %[^a-z]:不取a到z的值。 %[^\n]&#xff1a;取非换行之前的值。printf("%5d", a):左边补 格式化&#xff1a;有正则在其中。 int main() {printf("%5d\n&quo…...

Revit教程:怎么关掉工具栏的实时提示?

一、Revit中如何关闭工具栏的实时帮助提示 如图1所示&#xff0c;Revit会对每一个命令有一个简单的图文说明&#xff0c;方便不熟悉软件的用户使用。对于已经熟悉软件的用户&#xff0c;会觉得鼠标在菜单上悬停时弹出的实时帮助页面很干扰使用&#xff0c;而且很占内存资源&…...

javascript 简介

JavaScript 是互联网上最流行的脚本语言&#xff0c;这门语言可用于 HTML 和 web&#xff0c;更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。JavaScript 是脚本语言JavaScript 是一种轻量级的编程语言。JavaScript 是可插入 HTML 页面的编程代码。JavaScript…...

医学图象分割常用损失函数(附Pytorch和Keras代码)

对损失函数没有太大的了解&#xff0c;就是知道它很重要&#xff0c;搜集了一些常用的医学图象分割损失函数&#xff0c;学习一下&#xff01; 医学图象分割常见损失函数前言1 Dice Loss2 BCE-Dice Loss3 Jaccard/Intersection over Union (IoU) Loss4 Focal Loss5 Tvesky Loss…...

【新2023】华为OD机试 - 病菌感染(Python)

华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 病菌感染 题目 在一个地图中(地图有N*N个区域组成) 有部分区域被感染病菌 感染区域每天都会把周围上下左右的四个区域感染 请根据给定的地图计算多少天以后全部区域都会被感染 如果初始地图上所有区域都…...

QGIS中进行批量坡向计算

QGIS中进行坡向计算1. 坡向计算中的Z因子&#xff08;垂直单位与水平单位的比值&#xff09;2. 坡向计算步骤坡度计算的姊妹篇–坡向计算来了 1. 坡向计算中的Z因子&#xff08;垂直单位与水平单位的比值&#xff09; z 因子是一个转换因子&#xff0c;当输入表面的垂直坐标&…...

Redis持久化机制

一、RDB RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&#xff09;&#xff0c;也被叫做Redis数据快照。 RDB是Redis默认的持久化机制 - RDB持久化文件&#xff0c;速度比较快&#xff0c;而且存储的是一个二进制的文件&#xff0c;传输起来很方便。 - RD…...

2、VUE面试题

1, 如何让CSS只在当前组件中起作用&#xff1f;在组件中的style前面加上scoped2、<keep-alive></keep-alive>的作用是什么?keep-alive 是 Vue 内置的一个组件&#xff0c;可以使被包含的组件保留状态&#xff0c;或避免重新渲染。3, vue组件中如何获取dom元素?使…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...