Spring ServiceLocatorFactoryBean 小结

news2024/12/31 7:14:59

前言

偶然看到一篇微信公众号文章的分享 https://mp.weixin.qq.com/s/11VKseROGVcJHPCJ8xQ3XA,感觉挺有意思,在这里记录下。
为什么感觉有意思呢?是因为它通过spring 提供的ServiceLocatorFactoryBean 来实现服务定位模式,将服务的提供者和具体实现进行了解耦,你可以使用简单工厂模式来实现,但是不够友好,原因在于你用工厂模式的时候需要在工厂类里面维护创建具体实现类的创建,非真正意义的上的解耦,而本文要介绍的就能做到这一点,如下是示例。


示例:依据不同的文件类型来模拟解析文件

一、代码示例

1、我需要定义一个解析工厂,没错他就是接口,没有具体实现

// 解析工厂
public interface ParserFactory {
    Parser getParser(ContentType contentType);
}
// 文件类型枚举
public enum ContentType {
    JSON,
    CSV
}

2、我需要一个解析接口,用于不同类型的文件解析

public interface Parser {
    List parse(Reader r);
}

3、模拟实现两个解析类,CSV/JSON

@Component("CSV")
public class CSVParser implements Parser {
    @Override
    public List parse(Reader r) {
        System.out.println("parser csv file");
        return null;
    }
}

@Component("JSON")
public class JSONParser implements Parser {
    @Override
    public List parse(Reader r) {
        System.out.println("parser json file");
        return null;
    }
}

4、以上都具备了,那我要咋么用呢?这时需要有个客户端类帮助我们获取解析器类型

@Service
public class Client {
    @Autowired(required = false)
    private ParserFactory parserFactory;

    public List getAll(ContentType contentType) {

        // 关键点,直接根据类型获取
        return parserFactory
                .getParser(contentType)
                .parse(null); // 传入不同的文件读取Reader
    }
}

有么有注意到,这里的parserFactory 我只定义了接口,并没有实现,它是怎么注入的?

5、通过ServiceLocatorFactoryBean注入ParserFactory

@Configuration
public class ParserConfig {

    @Bean("parserFactory")
    public FactoryBean serviceLocatorFactoryBean() {
        ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
        // 设置服务定位接口
        factoryBean.setServiceLocatorInterface(ParserFactory.class);
        return factoryBean;
    }
}

6、现在这些接口以及client都有了,我要怎么用呢?很简单,如下

@RestController
@RequestMapping("/test")
public class MyController{

    @Autowired
    private Client client;

    @Operation(summary = "测试接口调用")
    @GetMapping("/{type}")
    public String test(@PathVariable String type) throws Exception {
        client.getAll(ContentType.valueOf(type.toUpperCase()));
        return "ok";
    }
}

到这里,你可以发起请求用于测试:curl -X GET “http://localhost:8080/test/csv”

二、原理探究

1.ServiceLocatorFactoryBean 是什么?ParserFactory它只是一个接口什么也没干,为什么就能找到Parser的具体实现类呢?

这时因为有个内部类实现 ServiceLocatorInvocationHandler 它利用了我们提供的ContentType,也即为bean的name来获取具体的实现类的,

  private Object invokeServiceLocatorMethod(Method method, Object[] args) throws Exception {
            Class<?> serviceLocatorMethodReturnType = this.getServiceLocatorMethodReturnType(method);

            try {
            	// 获取我们传入的bean name
                String beanName = this.tryGetBeanName(args);
                Assert.state(ServiceLocatorFactoryBean.this.beanFactory != null, "No BeanFactory available");
                // 如果 bean name不为空则通过beanFactory去加载指定名称的bean实例
                return StringUtils.hasLength(beanName) ? ServiceLocatorFactoryBean.this.beanFactory.getBean(beanName, serviceLocatorMethodReturnType) : ServiceLocatorFactoryBean.this.beanFactory.getBean(serviceLocatorMethodReturnType);
            } catch (BeansException var5) {
                if (ServiceLocatorFactoryBean.this.serviceLocatorExceptionConstructor != null) {
                    throw ServiceLocatorFactoryBean.this.createServiceLocatorException(ServiceLocatorFactoryBean.this.serviceLocatorExceptionConstructor, var5);
                } else {
                    throw var5;
                }
            }
        }

比如我们这里为JSONParser 起的名字叫 JSON,就是通过它去加载 JSONParser 然后执行具体的代码。

@Component("JSON")
public class JSONParser implements Parser {
    @Override
    public List parse(Reader r) {
        System.out.println("parser json file");
        return null;
    }
}

如下图所示:
在这里插入图片描述

2. ServiceLocatorFactoryBean的作用

其实ServiceLocatorFactoryBean 用于查找 Bean 的。我们提供的工厂类交给他通过bean name来获取具体实现的单例bean,从而实现业务和定义的解耦,非常省事。

总结

服务定位模式Service Locator Pattern来解决,它帮助我们消除紧耦合实现及其依赖性,并提出将服务与其具体类解耦。

参考:https://www.cnblogs.com/qiushuiyu-108/p/17140900.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/708311.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux-2.6.22.6内核i2c驱动框架源码分析

i2c是常见的通信协议&#xff0c;协议比较简单&#xff0c;只有数据和时钟两条线&#xff08;SDA和SCL&#xff09;&#xff0c;i2c的通信分为主机和从机&#xff0c;主机一般占主导地位&#xff0c;从机可以有多个。 i2c通信的数据格式为(SDA上的数据)&#xff1a;开始的7位里…

【完美复现】面向配电网韧性提升的移动储能预布局与动态调度策略【IEEE33节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

机器学习实战8-基于XGBoost和LSTM的台风强度预测模型训练与应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下机器学习实战8-基于XGBoost和LSTM的台风强度预测模型训练与应用&#xff0c;今年夏天已经来了&#xff0c;南方的夏天经常会有台风登陆&#xff0c;给人们生活带来巨大的影响&#xff0c;本文主要基于XGBoost模型和…

Python3 错误和异常 | 菜鸟教程(十五)

目录 一、简述 二、语法错误 三、异常 四、异常处理 &#xff08;一&#xff09;try/except 1、异常捕捉可以使用 try/except 语句。 2、以下例子中&#xff0c;让用户输入一个合法的整数&#xff0c;但是允许用户中断这个程序&#xff08;使用 Control-C 或者操作系统提供…

ChatGPT从入门到精通学习路线

课程名称适应人群 ChatGPT从入门到精通&#xff0c;一站式掌握办公自动化/爬虫/数据分析和可视 点击上述名称&#xff0c;学习完整视频 全面AI时代就在转角&#xff0c;道路已经铺好了“局外人”or“先行者”就在此刻等你决定 1、对ChatGPT感兴趣并希望有人手把手教学的新手 …

apex/amp 安装问题解决

如何安装&#xff1a; 首先 pip uninstall apex卸载、apex文件夹也删除&#xff0c; 重新安装&#xff0c;具体安装步骤如下&#xff1a; git clone https://www.github.com/nvidia/apex cd apex python setup.py install --cuda_ext --cpp_ext 只要出现了下面的语句就是完成…

人工智能数学基础2:利用SciPy中的数值积分常用函数求定积分

利用SciPy中的数值积分常用函数求定积分 21/82.625 方法一&#xff1a;在 SciPy 库中&#xff0c;可以使用 quad 函数来进行数值积分。具体实现代码如下&#xff1a; from scipy.integrate import quaddef integrand(x):return x**2 1/x**4 # 定义被积函数result, error q…

vue+leaflet笔记之地图卷帘

vueleaflet笔记之地图卷帘 本文介绍了Web端使用Leaflet开发库实现地图卷帘效果的方法 (底图来源:中科星图)&#xff0c;结合leaflet-side-by-side插件可以快速简单地实现地图分屏对比效果 &#xff0c;示例效果如下图所示。 开发环境 Vue开发库&#xff1a;3.2.37 & Leaf…

FPGA-DFPGL22学习5-VERILOG

系列文章之 上章 FPGA-DFPGL22学习4-仿真平台学习 文章目录 系列文章之 上章前言一、Verilog 简介二、Verilog基础1.逻辑值2.进制3.标识符4.数据类型寄存器类型线网类型参数类型 5.运算符 三、Verilog 程序框架1.注释2.关键字3.程序框架 四、Verilog 程序语句1.结构语句2.赋值…

微信小程序+SpringBoot接入后台服务,接口数据来自后端

前言 前两天开发了一个微信小程序项目&#xff0c;只不过接口数据是自己设置的假数据。然后我就想将这些假数据替换掉。这些数据来自接口&#xff0c;之前做过前后端分离的项目&#xff0c;我就想能不能直接调用那些后端数据接口。结果是可以的。以下是自己编写的部分方法 步骤…

卷积神经网络--猫狗系列之下载、导入数据集

(由于是学习&#xff0c;所以文章会有一些报错及解决办法) 在Kaggle()获取数据集&#xff1a;&#xff08;没有账号先去注册一个账号&#xff0c;在注册时可能会出现的问题见Kaggle注册出现一排“Captcha must be filled out.”&#xff01;&#xff09; https://www.kaggle.…

DOM编程事件与简单编程

文章目录 事件绑定绑定式事件监听方法event 事件对象client、offsetkeyCode 键盘事件事件冒泡阻止浏览器默认行为 DOM编程用户名输入框长度限制鼠标移入移出复选框全选DOM编程实现动态时钟第一种&#xff1a;第二种&#xff1a;第三种&#xff1a; 事件绑定 DOM编程中的事件&a…

excel只显示想要的内容

是 后面的FG等列是不需要的&#xff0c;选择F列&#xff0c;ctrl shift 右箭头 。选中后隐藏。

Ansible创建逻辑卷

Ansible创建逻辑卷&#xff1a; 环境准备&#xff1a; 清单文件&#xff1a; [dev] 192.168.110.129 [prod] 192.168.110.132 [all:vars] ansible_userroot ansible_passwordredhat磁盘准备&#xff1a; 在一台主机上添加一块sata接口的磁盘&#xff0c;一块不添加。 192.…

Linux--获取一长串目录的结构指令:tree

注意&#xff1a;这个tree指令不是Linux自带的&#xff0c;需要下载 yum install -y tree (-y的作用是免确定) 示例&#xff1a;

UE5 读写本地JSON,发送HTTP请求(get)

UE5 读写本地JSON&#xff0c;发送HTTP请求&#xff08;get&#xff09; 没有使用插件&#xff0c;就用UE提供的库开发&#xff08;推荐使用插件VaRest在虚幻商城里有&#xff09; PCHUsage PCHUsageMode.UseExplicitOrSharedPCHs;PublicDependencyModuleNames.AddRange(new …

win10 编译hadoop源码报错

报错信息&#xff1a; 信息: 用提供的模式无法找到文件。 "devenv command was not found. Verify your compiler installation level."解决方案 右键&#xff0c;以管理员身份打开 之后再次执行mvn 命令即可. 也可以再打开的时候先执行一下命令&#xff1a; dev…

数字化是信息化的升级吗?数字化信息化这两者有什么联系和区别?

也可以这样说吧&#xff0c;但总是太抽象&#xff0c;不准确的&#xff0c;两者还是有很大区别的。 首先来看信息化、数字化具体是什么意思 想要明白两者之间的差异&#xff0c;首先要搞清楚他们的出处—— 所谓信息化、数字化还有现在提很多的智能化&#xff0c;其实都是从…

如何免费将springboot+vue项目部署上线(云服务器+宝塔面板)

本文整个流程是在博主完成一次项目上线全过程后复盘的记录&#xff0c;有没有写到的细节不清楚的可以私聊提问&#xff0c;这里选用的是阿里云服务器&#xff0c;阿里云对学生用户可以免费使用一个月服务器&#xff0c;不定期也有活动&#xff0c;我白嫖了7个月服务器&#xff…

ZYNQ——脉宽调制之呼吸灯实现

文章目录 原理简介实验代码软件仿真板上验证 原理简介 呼吸灯的实现过程就是把不同占空比的脉冲输出后加在LED上&#xff0c;LED灯就会显示不同的亮度&#xff0c;通过不断地调节方波的占空比&#xff0c;LED灯的亮度也会跟着变化&#xff0c;看起来就像是“呼吸”一样。 要得…