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

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(推荐)

这种是开发中使用较多的一种方案。SqlSessionFactoryBeanShiroFilterFactoryBean 。。。
首先,我们需要创建一个 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&#xff0c;我们往往不能直接 new 出来&#xff0c;这些 Bean 如果需要注册到 Spring 容器中&#xff0c;我们就需要使用工厂类。 比如我们项目中经常使用的okhttp: 如果我们想把OkHttpClient注册到Spring容器中&#xff0c;该怎么做? …...

WPF网格拖动自动布局效果

WPF网格拖动自动布局效果 使用Canvas和鼠标相关事件实现如下的效果: XAML代码: <Window x:Class="CanvasTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:...

肯德尔秩相关系数(Kendall‘s Tau)排名

肯德尔秩相关系数&#xff08;Kendall’s Tau&#xff09;是一种用于衡量两个排列之间相似性的统计指标&#xff0c;它考虑了元素之间的顺序关系而不考虑具体数值。该系数被广泛用于排序、排名和比较不同实验结果的相关性等领域。 具体而言&#xff0c;肯德尔秩相关系数衡量了…...

电脑怎么把视频转换gif动图?视频生成gif的操作步骤

如果你也想把一些精彩的视频转gif图片&#xff08;https://www.gif.cn&#xff09;的话&#xff0c;今天的文章你可千万不要错过&#xff0c;利用专业的视频转gif工具&#xff0c;轻松在线视频转gif&#xff0c;操作简单又方便&#xff0c;支持电脑、手机双端操作&#xff0c;赶…...

使用 docker 搭建 granfana+prometheus 监控平台监控测试服务器资源

互联网发展的今天&#xff0c;人们对互联网产品的用户体验要求也越来越高&#xff0c;企业为了能提供更优质的用户体验&#xff0c;就会绞尽脑汁想尽各种办法。而对于服务器的资源监控&#xff0c;搭建一个资源监控平台&#xff0c;就是一个很好的维护优质服务的保障平台。利用…...

一、MQ的基本概念

1、初识MQ MQ全称是Message Queue&#xff0c;消息队列&#xff0c;多用于系统之间进行异步通信。队列的概念数据结构中有详细介绍过&#xff0c;先进先出&#xff0c;消息队列就是存储消息的数据结构。 同步调用和异步调用两者之间的区别&#xff1a; 同步调用&#xff1a;发…...

Android面试题:MVC、MVP、MVVM

MVC模式&#xff1a; MVC结构&#xff1a; 1.MVC(Model-View-Controller) 2.Model:对数据库的操作、对网络等的操作都应该在Model里面处理&#xff0c;当然对业务计算&#xff0c;变更等操作也是必须放在的该层的。 3.View:主要包括一下View及ViewGroup控件&#xff0c;可以是…...

vue js 回调函数 异步处理 为什么要 let that = this

1 异步就是开个事务(只有主线程 等主线程空闲),用that 值 做处理,然后返回处理结果,而that的值是开启事务那一刻的this的值.而在主线程处理的时候,this的一直在变化, that的值保留在那一刻 ps 或是将本obj 传递给其他的obj使用处理 ps 开启新事务或开启新子线程都是 在新的ob…...

前端面试:【算法与数据结构】常见数据结构解析

在计算机科学中&#xff0c;数据结构是组织和存储数据的方式。精通常见的数据结构对于解决计算机科学和编程问题至关重要。本文将深入探讨常见的数据结构&#xff1a;数组、链表、栈、队列和哈希表&#xff0c;以帮助你建立坚实的数据结构基础。 1. 数组&#xff08;Array&…...

RTSP/Onvif视频服务器EasyNVR安防视频云服务平台出现崩溃并重启的情况解决方案

EasyNVR安防视频云服务平台的特点是基于RTSP/Onvif协议将前端设备统一接入&#xff0c;在平台进行转码、直播、处理及分发&#xff0c;在安防监控场景中&#xff0c;EasyNVR可实现实时监控、云端录像、云存储、告警、级联等视频能力&#xff0c;极大满足行业的视频监控需求。 有…...

软考高级系统架构设计师系列论文九十四:论计算机网络的安全性设计

软考高级系统架构设计师系列论文九十四:论计算机网络的安全性设计 一、计算机网络安全性设计相关知识点二、摘要三、正文四、总结一、计算机网络安全性设计相关知识点 软考高级系统架构设计师:计算机网络...

jenkins Linux如何修改jenkins 默认的工作空间workspace

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

Mysql报错 mysqladmin flush-hosts

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

javaee idea创建maven项目,使用el和jstl

如果使用el表达式出现下图问题 解决办法 这是因为maven创建项目时&#xff0c;web.xml头部声明默认是2.3&#xff0c;这个默认jsp关闭el表达式 办法1 在每个需要用到el和jstl的页面的上面加一句: <% page isELIgnored"false" %> 方法2 修改web.xml文件开…...

同一个服务器发布两个前端(网站)

一开始怎么设置都是505&#xff0c;后来把网站文件的位置换到原已经发布成功的网站位置&#xff0c;就成功了。考虑应该是权限问题 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。 配置镜像源&#xff1a; yaml conda配置 vim ~/.condarc channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro/ - https://mirrors.tuna.ts…...

4.5 TCP优化

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

pdf太大怎么压缩大小?这样压缩文件很简单

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

【IMX6ULL驱动开发学习】09.Linux之I2C框架简介和驱动程序模板

参考&#xff1a;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)的语料库非常庞大&#xff0c;而且还在继续增长。随着BLOB占用空间的增加&#xff0c;将它们存储在我们传统的存储系统-- Haystack 中变得越来越低效。为了提高我们的存储效率(以Blob的有效复…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

Linux部署私有文件管理系统MinIO

最近需要用到一个文件管理服务&#xff0c;但是又不想花钱&#xff0c;所以就想着自己搭建一个&#xff0c;刚好我们用的一个开源框架已经集成了MinIO&#xff0c;所以就选了这个 我这边对文件服务性能要求不是太高&#xff0c;单机版就可以 安装非常简单&#xff0c;几个命令就…...