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的有效复…...
基于亚马逊云科技服务,构建大语言模型问答知识库
随着大语言模型效果明显提升,其相关的应用不断涌现呈现出越来越火爆的趋势。其中一种比较被广泛关注的技术路线是大语言模型(LLM)知识召回(Knowledge Retrieval)的方式,在私域知识问答方面可以很好的弥补通…...
SpingMVC拦截器-用户登录权限控制分析
视频链接:08-SpringMVC拦截器-用户登录权限控制代码实现2_哔哩哔哩_bilibili 114 1、做了一个用户跟角色添加的相关操作 1.1 这个后台工程,没有进行相关操作也能够进行登录: 2、现在我做一个用户的权限控制,如果当前我没有进行操…...
MDTA模块(Restormer)
From a layer normalized tensor Y ∈ R H ^ W ^ C ^ \mathbf{Y} \in \mathbb{R}^{\hat{H} \times \hat{W} \times \hat{C}} Y∈RH^W^C^, our MDTA first generates query ( Q ) (\mathbf{Q}) (Q), key ( K ) (\mathbf{K}) (K) and value ( V ) (\mathbf{V}) (V) project…...
C++ 新特性 | C++ 11 | decltype 关键字
一、decltype 关键字 1、介绍 decltype 是 C11 新增的一个用来推导表达式类型的关键字。和 auto 的功能一样,用来在编译时期进行自动类型推导。引入 decltype 是因为 auto 并不适用于所有的自动类型推导场景,在某些特殊情况下 auto 用起来很不方便&…...
2023国赛数学建模思路 - 案例:退火算法
文章目录 1 退火算法原理1.1 物理背景1.2 背后的数学模型 2 退火算法实现2.1 算法流程2.2算法实现 建模资料 ## 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 退火算法原理 1.1 物理背景 在热力学上&a…...
ubuntu20.04 编译安装运行emqx
文章目录 安装依赖编译运行登录dashboard压力测试 安装依赖 Erlang/OTP OTP 24 或 25 版本 apt-get install libncurses5-dev sudo apt-get install erlang如果安装的erlang版本小于24的话,可以使用如下方法自行编译erlang 1.源码获取 wget https://github.com/erla…...
ARM linux ALSA 音频驱动开发方法
+他V hezkz17进数字音频系统研究开发交流答疑群(课题组) 一 linux ALSA介绍 ALSA (Advanced Linux Sound Architecture) 是一个用于提供音频功能的开源软件框架。它是Linux操作系统中音频驱动程序和用户空间应用程序之间的接口。ALSA 提供了访问声卡硬件的低级别API,并支持…...
设计模式二十三:模板方法模式(Template Method Pattern)
定义了一个算法的框架,将算法的具体步骤延迟到子类中实现。这样可以在不改变算法结构的情况下,允许子类重写算法的特定步骤以满足自己的需求 模版方法使用场景 算法框架固定,但具体步骤可以变化:当你有一个算法的整体结构是固定…...
[Linux]进程状态
[Linux]进程状态 文章目录 [Linux]进程状态进程状态的概念阻塞状态挂起状态Linux下的进程状态孤儿进程 进程状态的概念 了解进程状态前,首先要知道一个正在运行的进程不是无时无刻都在CPU上进行运算的,而是在操作系统的管理下,和其他正在运行…...
Python爬虫逆向实战案例(五)——YRX竞赛题第五题
题目:抓取全部5页直播间热度,计算前5名直播间热度的加和 地址:https://match.yuanrenxue.cn/match/5 cookie中m值分析 首先打开开发者工具进行抓包分析,从抓到的包来看,参数传递了查询参数m与f,同时页面中…...
美食推荐网站模板/经典软文案例和扶贫农产品软文
传送门:http://acm.hdu.edu.cn/showproblem.php?pid1823 Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem Description世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你―― 张…...
县工商局 网站建设/海外域名
前言 当实体类对象里面有字段A,叫做:width 数据库叫做:default_width。如下图: Columb(name "default_width") private String width;使用mybatis自己的Mapper查询,比如selectPrimarykey,是没有…...
网站建设目标 优帮云/微信朋友圈推广文案
开发环境(蓝色粗体字为特别注意内容)1,元器件:稳压二极管 电阻。 在日常使用的电子电路设计中,电源供电部分很重要,有时候操作不当,可能过压,可能反接,虽然发生的概率比较小,但是现实…...
win7 网站系统怎么做/网络营销与管理
本文目录: 1.等待、唤醒机制的原理 2.Lock和Condition 3.单生产者单消费者模式 4.使用Lock和Condition实现单生产单消费模式 5.多生产多消费模式(单面包) 6.多生产多消费模式 生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放…...
营销网站建设软件下载/百度网站提交
墨墨导读:本文来自墨天轮用户 肖杰 的投稿,介绍用BBED恢复删除数据的全过程。墨天轮主页:https://www.modb.pro/u/6722Oracle中delete行时,数据实际上并没有被删除。而是将行标记为已删除,并相应地调整空闲空间计数器和…...
安庆网站建设电话/百度一下百度百科
Hello, 壹脑云读书圈的小伙伴们大家好,我是忍冬。 经常听到身边的朋友抱怨,现在的女孩子真的好难追呀。 又要长得帅,又要体贴,又要有能力有上进心,最好还要有车有房。 其实我觉得,雨林中的雄…...