大数跨境
0
0

强!Spring Boot 通过服务定位干掉if-else

强!Spring Boot 通过服务定位干掉if-else Spring全家桶实战案例
2025-06-22
0
导读:强!Spring Boot 通过服务定位干掉if-else
Spring Boot 3实战案例锦集PDF电子书已更新至130篇!
图片

🎉🎉《Spring Boot实战案例合集》目前已更新136个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 简介

相信在项目中都遇到过这样的需求,根据不同的传入类型调用同一个接口的不同实现类或服务处理逻辑。

例如,需要不同的解析器来处理不同的文件类型。例如,XML 文件由 XML 解析器处理,而 JSON 文件则由 JSON 解析器处理。

对于这样的场景,我们通常会在调用客户端中使用 if-else 语句。例如,如下代码示例:

public void processFile(String contentType, String filePath) {  if ("json".equalsIgnoreCase(contentType)) {    // ..  } else if ("xml".equalsIgnoreCase(contentType)) {    // ...  } else if ("csv".equalsIgnoreCase(contentType)) {    // ...  } else {    // ...  }}

当然我详细你大概率会使用下面这篇文章的方法来处理这种if-else:

优雅重构Spring Boot代码,我用这6种策略消灭if else

本篇文章将介绍另外一种使用 服务定位器模式(Service Locator Pattern)的方法。其核心思想是面向接口编程,帮助我们消除紧密耦合的实现,并减轻客户端对具体实现类的依赖。

2.实战案例

2.1 定义枚举

在该枚举类中,我们定义了将要处理的文件类型。

public enum ContentType {  JSON(TypeConstants.JSON_PARSER),   XML(TypeConstants.XML_PARSER),   CSV(TypeConstants.CSV_PARSER);
  private final String parserName;  ContentType(String parserName) {    this.parserName = parserName;  }  @Override  public String toString() {    return this.parserName;  }  public interface TypeConstants {    String CSV_PARSER = "csvParser";    String JSON_PARSER = "jsonParser";    String XML_PARSER = "xmlParser";  }}

2.2 定义解析器接口

针对不同的文件类型,我们只需要定义对应的接口实现即可。

public interface Parser {  Map<StringObjectparse(Reader r);}

针对上面定义的3种文件类型,分别实现对应的Parser。

@Component(TypeConstants.CSV_PARSER)public class CSVParser implements Parser {  @Override  public Map<StringObjectparse(Reader r) {    return Map.of("csv""csv文件解析成功") ;  } }@Component(TypeConstants.JSON_PARSER)public class JSONParser implements Parser {  @Override  public Map<StringObjectparse(Reader r) {    return Map.of("json""json文件解析成功") ;  }}@Component(TypeConstants.XML_PARSER)public class XMLParser implements Parser {  @Override  public Map<StringObjectparse(Reader r) {    return Map.of("xml""xml文件解析成功") ;  }}

注意,我们这里的beanName。我们接下来将直接通过beanName自动的查找对应解析器实现。

2.3 定义服务定位器接口

该接口中只有一个方法 getParser,该方法接受一个内容类型(contentType)作为参数,并返回 Parser 接口。

public interface ParserFactory {  Parser getParser(ContentType contentType);}

我们将直接通过参数ContentType来获取对应的Parser具体实现。

2.4 配置ServiceLocatorFactoryBean

该类是我们的重点,我们就是通过它来定义具体的Parser实现。我们配置 ServiceLocatorFactoryBean 来使用 ParserFactory 作为服务定位器接口。ParserFactory 接口不需要具体的实现类

@Configurationpublic class ParserConfig {  @Bean("parserFactory")  ServiceLocatorFactoryBean serviceLocatorFactoryBean() {    ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();    factoryBean.setServiceLocatorInterface(ParserFactory.class);    return factoryBean;  }}

如上配置后,ServiceLocatorFactoryBean底层会生成ParserFactory的代理类,对应的 InvocationHandler 实现会根据当前调用的方法参数(第一个参数)来获取对应的beanName。

2.5 测试使用

接下来,在使用 Parser 时就无需关心去引入具体的实现了。通过上面的ServiceLocatorFactoryBean 可以直接根据类型获取具有相应功能的 Parser 接口。

@Servicepublic class ParserService {  private final ParserFactory parserFactory;  public ParserService(ParserFactory parserFactory) {    this.parserFactory = parserFactory;  }  public Map<StringObjectgetData(ContentType contentType) {    Parser parser = parserFactory.getParser(contentType) ;    InputStreamReader reader = null ;    return parser.parse(reader);  }}

接下来,我们定义一个Runner进行测试

@Componentpublic class ParserRunner implements CommandLineRunner {  private final ParserService parserService ;  public ParserRunner(ParserService parserService) {    this.parserService = parserService;  }  @Override  public void run(String... args) throws Exception {    Map<String, Object> data = this.parserService.getData(ContentType.CSV) ;    System.err.println(data) ;    data = this.parserService.getData(ContentType.JSON) ;    System.err.println(data) ;    data = this.parserService.getData(ContentType.XML) ;    System.err.println(data) ;  }}

启动服务后,控制台输出结果如下:

2.6 工作原理

如下图是ServiceLocator服务定位的工作原理:

总结:服务定位器模式消除了客户端对具体实现的依赖。以下是 Martin Fowler 文章中的一段话,它总结了该模式的核心思想:

“服务定位器的基本思想是拥有一个对象,该对象知道如何获取应用程序可能需要的所有服务。”



以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

如何在Spring Boot中优雅地加载配置?这些方法你必须掌握!

Spring Boot中记录JDBC、JPA及MyBatis执行SQL及参数的正确姿势

非常实用!玩转 Spring Boot 接口参数类型转换,支持任意场景

优雅!Spring Boot 一个注解轻松实现敏感词检查,支持多场景

基于 Spring Boot 玩转JPA各种锁的应用(乐观锁,悲观锁)

处理Null的神器Optional

实体与DTO如何转换?这个工具很厉害

自己动手实现精简版SpringBoot原来如此简单

优雅!SpringBoot详细记录SQL执行耗时情况

Spring Boot 优雅处理 JSON动态属性

请不要自己写!Spring Boot非常实用的内置功能

图片
图片
图片
图片
图片
图片
图片
图片
图片

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832