Spring注入外部 工厂类Bean
问题
对于一些使用建造者模式的 Bean,我们往往不能直接 new 出来,这些 Bean 如果需要注册到 Spring 容器中,我们就需要使用工厂类。
比如我们项目中经常使用的okhttp
: 如果我们想把OkHttpClient注册到Spring容器中,该怎么做?
public class App {public static void main(String[] args) {//通过建造者模式去创建 OkHttpClient 对象OkHttpClient client = new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();//构建一个具体的请求Request getRequest = new Request.Builder().get().url("https://www.baidu.com").build();Call call = client.newCall(getRequest);CountDownLatch countDownLatch = new CountDownLatch(1);//异步执行网络请求,处理请求结果;如果直接调用call.execute()就是同步,会阻塞call.enqueue(new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {countDownLatch.countDown();}// 这个就是请求成功的回调函数@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {countDownLatch.countDown();System.out.println("response.body().string() = " + response.body().string());}});//会判断计数器是否为 0,如果为 0,才会继续执行后续的代码,否则就暂停在这里try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
又比如GSON
: 这里的Gson对象也不是直接 new 出来的,而是通过一个GsonBuilder对象建造出来的。
public class App {public static void main(String[] args) {User user = new User();user.setName("hogen");user.setBirthday(new Date());Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();String toJson = gson.toJson(user);System.out.println(toJson);
}
解决方案
方法一 静态工厂
通过一个工厂方法,将 Bean 构建好之后,注入到 Spring 容器中,需要注意的是,这个工厂方法是一个静态方法
// 静态工厂,顾名思义,可以直接通过类名.方法名调用
public class OkHttpClientStaticFactory {private static OkHttpClient okHttpClient;static {okHttpClient = new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();}public static OkHttpClient getInstance() {return okHttpClient;}
}
然后在 XML 文件中配置静态工厂:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><bean class="org.example.OkHttpClientStaticFactory" id="okHttpClient" factory-method="getInstance"/>
</beans>
XML 中配置的时候,需要注意,虽然我们看起来向 Spring 容器中注册的是一个静态工厂类的对象,但是实际上,最终会调用对应的方法 factory-method
,向 Spring
容器中注册一个 OkHttpClient
对象,而且该对象还是单例的。
public class App {public static void main(String[] args) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");OkHttpClient client1 = ctx.getBean("okHttpClient", OkHttpClient.class);OkHttpClient client2 = ctx.getBean("okHttpClient", OkHttpClient.class);System.out.println("client2 = " + client2);System.out.println(client2 == client1);}
}
输出:
client2 = okhttp3.OkHttpClient@41fecb8b
true
方法一 实例工厂
此种情况,工厂方法是一个实例方法(得先有对象,再调用方法)。
public class OkHttpClientStaticFactory {private static OkHttpClient okHttpClient;static {okHttpClient = new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();}public static OkHttpClient getInstance() {return okHttpClient;}
}
然后在 XML 文件中进行配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="org.example.OkHttpClientInstanceFactory" id="okHttpClientInstanceFactory"/><bean class="org.example.OkHttpClientInstanceFactory" factory-bean="okHttpClientInstanceFactory" factory-method="getInstance" id="okHttpClient"/>
</beans>
那么需要注意的是,实例工厂中,工厂方法无法直接调用,必须先有一个实例对象,然后才能调用工厂方法。当然,最终注册到 Spring 容器中的 Bean 也是单例的。
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
OkHttpClient client1 = ctx.getBean("okHttpClient", OkHttpClient.class);
OkHttpClient client2 = ctx.getBean("okHttpClient", OkHttpClient.class);
System.out.println("client2 = " + client2);
System.out.println(client2 == client1);
方法一 FactoryBean(推荐)
这种是开发中使用较多的一种方案。SqlSessionFactoryBean
、 ShiroFilterFactoryBean
。。。
首先,我们需要创建一个 OkHttpClientFactoryBean
:
/*** 注意这个命名是有规则的,一般叫做 xxxFactoryBean,看到这个名字,就知道最终生成的 Bean 实际上是 xxx*/
public class OkHttpClientFactoryBean implements FactoryBean<OkHttpClient> {/*** 返回具体的实例对象** @return* @throws Exception*/@Overridepublic OkHttpClient getObject() throws Exception {return new OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build();}/*** 返回的实例对象的类型** @return*/@Overridepublic Class<?> getObjectType() {return OkHttpClient.class;}/*** 是否是单例模式* 如果为 false,就相当于 scope 为 prototype,默认该值为 true** @return*/@Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();}
}
然后在 XML 文件中进行配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="org.example.OkHttpClientFactoryBean" id="okHttpClient"/>
</beans>
当然最终获取到的还是okHttpClient
对象
public class App {public static void main(String[] args) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");OkHttpClient okHttpClient = ctx.getBean("okHttpClient", OkHttpClient.class);System.out.println(okHttpClient);}
}
输出:
okhttp3.OkHttpClient@693fe6c9
那么如何获取到这个工厂 Bean 呢?只需要 id 前面添加一个 & 符号,就可以获取到 FactoryBean。
public class App {public static void main(String[] args) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");Object bean = ctx.getBean("&okHttpClient");System.out.println(bean.getClass());}
}
输出:
class org.example.OkHttpClientFactoryBean
相关文章:
Spring注入外部 工厂类Bean
问题 对于一些使用建造者模式的 Bean,我们往往不能直接 new 出来,这些 Bean 如果需要注册到 Spring 容器中,我们就需要使用工厂类。 比如我们项目中经常使用的okhttp: 如果我们想把OkHttpClient注册到Spring容器中,该怎么做? …...

WPF网格拖动自动布局效果
WPF网格拖动自动布局效果 使用Canvas和鼠标相关事件实现如下的效果: XAML代码: <Window x:Class="CanvasTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:...
肯德尔秩相关系数(Kendall‘s Tau)排名
肯德尔秩相关系数(Kendall’s Tau)是一种用于衡量两个排列之间相似性的统计指标,它考虑了元素之间的顺序关系而不考虑具体数值。该系数被广泛用于排序、排名和比较不同实验结果的相关性等领域。 具体而言,肯德尔秩相关系数衡量了…...

电脑怎么把视频转换gif动图?视频生成gif的操作步骤
如果你也想把一些精彩的视频转gif图片(https://www.gif.cn)的话,今天的文章你可千万不要错过,利用专业的视频转gif工具,轻松在线视频转gif,操作简单又方便,支持电脑、手机双端操作,赶…...
使用 docker 搭建 granfana+prometheus 监控平台监控测试服务器资源
互联网发展的今天,人们对互联网产品的用户体验要求也越来越高,企业为了能提供更优质的用户体验,就会绞尽脑汁想尽各种办法。而对于服务器的资源监控,搭建一个资源监控平台,就是一个很好的维护优质服务的保障平台。利用…...

一、MQ的基本概念
1、初识MQ MQ全称是Message Queue,消息队列,多用于系统之间进行异步通信。队列的概念数据结构中有详细介绍过,先进先出,消息队列就是存储消息的数据结构。 同步调用和异步调用两者之间的区别: 同步调用:发…...
Android面试题:MVC、MVP、MVVM
MVC模式: MVC结构: 1.MVC(Model-View-Controller) 2.Model:对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算,变更等操作也是必须放在的该层的。 3.View:主要包括一下View及ViewGroup控件,可以是…...
vue js 回调函数 异步处理 为什么要 let that = this
1 异步就是开个事务(只有主线程 等主线程空闲),用that 值 做处理,然后返回处理结果,而that的值是开启事务那一刻的this的值.而在主线程处理的时候,this的一直在变化, that的值保留在那一刻 ps 或是将本obj 传递给其他的obj使用处理 ps 开启新事务或开启新子线程都是 在新的ob…...
前端面试:【算法与数据结构】常见数据结构解析
在计算机科学中,数据结构是组织和存储数据的方式。精通常见的数据结构对于解决计算机科学和编程问题至关重要。本文将深入探讨常见的数据结构:数组、链表、栈、队列和哈希表,以帮助你建立坚实的数据结构基础。 1. 数组(Array&…...

RTSP/Onvif视频服务器EasyNVR安防视频云服务平台出现崩溃并重启的情况解决方案
EasyNVR安防视频云服务平台的特点是基于RTSP/Onvif协议将前端设备统一接入,在平台进行转码、直播、处理及分发,在安防监控场景中,EasyNVR可实现实时监控、云端录像、云存储、告警、级联等视频能力,极大满足行业的视频监控需求。 有…...
软考高级系统架构设计师系列论文九十四:论计算机网络的安全性设计
软考高级系统架构设计师系列论文九十四:论计算机网络的安全性设计 一、计算机网络安全性设计相关知识点二、摘要三、正文四、总结一、计算机网络安全性设计相关知识点 软考高级系统架构设计师:计算机网络...

jenkins Linux如何修改jenkins 默认的工作空间workspace
由于jenkins默认存放数据的目录是/var/lib/jenkins,一般这个var目录的磁盘空间很小的,就几十G,所以需要修改jenkins的默认工作空间workspace 环境 jenkins使用yum安装的 centos 7 正题 1 查看jenkins安装路径 [rootlocalhost jenkins_old_data]# rpm…...

Mysql报错 mysqladmin flush-hosts
出现这个的原因是错误连接达到数据库设置的最大值。 此时需要释放重置连接最大值。 进入mysql使用命令 flush-hosts;环境说明: 内网测试服务器192.168.18.251 为WEB服务器,安装了mysql; 内网音视频转码服务器192.168.18.253安装了转码工具࿰…...

javaee idea创建maven项目,使用el和jstl
如果使用el表达式出现下图问题 解决办法 这是因为maven创建项目时,web.xml头部声明默认是2.3,这个默认jsp关闭el表达式 办法1 在每个需要用到el和jstl的页面的上面加一句: <% page isELIgnored"false" %> 方法2 修改web.xml文件开…...
同一个服务器发布两个前端(网站)
一开始怎么设置都是505,后来把网站文件的位置换到原已经发布成功的网站位置,就成功了。考虑应该是权限问题 server {listen 80;server_name localhost;# https配置参考 start#listen 443 ssl;# 证书直接存放 /docker/nginx/cert/ 目录下即…...
部署常用指南
https://docs.conda.io/en/latest/miniconda.html#installing 环境配置 安装和配置 Anaconda 安装 Anaconda。 配置镜像源: yaml conda配置 vim ~/.condarc channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro/ - https://mirrors.tuna.ts…...

4.5 TCP优化
TCP 三次握手的性能提升 三次握手的过程在一个 HTTP 请求的平均时间占比 10% 以上,所以要正确使用三次握手的中参数,需要先用netstat命令查看是哪个握手阶段出了问题,主动发起连接的客户端优化相对简单些,而服务端需要监听端口&a…...

pdf太大怎么压缩大小?这样压缩文件很简单
工作和学习中,用到PDF文件的机会还是比较多的,但有时候PDF文件过大会给我们带来困扰,比如上传PDF文件时会因超出系统大小导致无法上传,这时候简单的解决方法就是压缩PDF文件,下面就来看看具体的操作方法吧~ 方法一&…...

【IMX6ULL驱动开发学习】09.Linux之I2C框架简介和驱动程序模板
参考:Linux之I2C驱动_linux i2c驱动_风间琉璃•的博客-CSDN博客 目录 一、I2C驱动框架简介 1.1 I2C总线驱动 1.2 I2C设备驱动 二、I2C总线-设备-驱动模型 2.1 i2c_driver 2.2 i2c_client 2.3 I2C 设备数据收发和处理 三、Linux I2C驱动程序模板…...

【seaweedfs】3、f4: Facebook’s Warm BLOB Storage System 分布式对象存储的冷热数据
论文地址 Facebook的照片、视频和其他需要可靠存储和快速访问的二进制大型对象(BLOB)的语料库非常庞大,而且还在继续增长。随着BLOB占用空间的增加,将它们存储在我们传统的存储系统-- Haystack 中变得越来越低效。为了提高我们的存储效率(以Blob的有效复…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...