0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一种扩展Spring控制反转的绝妙方法

jf_ro2CN3Fa 来源:JAVA旭阳 2024-01-10 09:41 次阅读

来源:JAVA旭阳

不知道大家在项目中有没有遇到过这样的场景,根据传入的类型,调用接口不同的实现类或者说服务,比如根据文件的类型使用 CSV解析器或者JSON解析器,在调用的客户端一般都是用if else去做判断,比如类型等于JSON,我就用JSON解析器,那如果新加一个类型的解析器,是不是调用的客户端还要修改呢?这显然太耦合了,本文就介绍一种方法,服务定位模式Service Locator Pattern来解决,它帮助我们消除紧耦合实现及其依赖性,并提出将服务与其具体类解耦。

文件解析器的例子

我们通过一个例子来告诉你如何使用Service Locator Pattern。

假设我们有一个从各种来源获取数据的应用程序,我们必须解析不同类型的文件,比如解析CSV文件和JSON文件。

1、定义一个类型的枚举

publicenumContentType{
JSON,
CSV
}

2、定义一个解析的接口

publicinterfaceParser{
Listparse(Readerr);
}

3、根据不同的文件类型有不同的实现类

//解析csv
@Component
publicclassCSVParserimplementsParser{
@Override
publicListparse(Readerr){..}
}

//解析json
@Component
publicclassJSONParserimplementsParser{
@Override
publicListparse(Readerr){..}
}

4、最后写一个调用的客户端,通过switch case根据不同的类型调用不同的实现

@Service
publicclassClient{
privateParsercsvParser,jsonParser;

@Autowired
publicClient(ParsercsvParser,ParserjsonParser){
this.csvParser=csvParser;
this.jsonParser=jsonParser;
}

publicListgetAll(ContentTypecontentType){
..

switch(contentType){
caseCSV:
returncsvParser.parse(reader);
caseJSON:
returnjsonParser.parse(reader);
..
}
}
..
}

可能大部分人都是像上面一样的方式实现的,也能正常运行,那深入思考下,存在什么问题吗?

现在假如产品经理提出了一个新需求要支持XML类型的文件,是不是客户端也要修改代码,需要在switch case中添加新的类型,这就导致客户端和不同的解析器紧密耦合。

那么有什么更好的方法呢?

应用Service Locator Pattern

没错,那就是用上我们的服务定位模式Service Locator Pattern。

1、让我们定义我们的服务定位器接口ParserFactory, 它有一个接受内容类型参数并返回Parser的方法。

publicinterfaceParserFactory{
ParsergetParser(ContentTypecontentType);
}

2、我们配置ServiceLocatorFactoryBean使用ParserFactory作为服务定位器接口,ParserFactory这个接口不需要写实现类。

@Configuration
publicclassParserConfig{

@Bean("parserFactory")
publicFactoryBeanserviceLocatorFactoryBean(){
ServiceLocatorFactoryBeanfactoryBean=newServiceLocatorFactoryBean();
//设置服务定位接口
factoryBean.setServiceLocatorInterface(ParserFactory.class);
returnfactoryBean;
}

}

3、设置解析器Bean的名称为类型名称,方便服务定位

//设置bean的名称和类型一致
@Component("CSV")
publicclassCSVParserimplementsParser{..}
@Component("JSON")
publicclassJSONParserimplementsParser{..}
@Component("XML")
publicclassXMLParserimplementsParser{..}

4、修改枚举, 添加XML

publicenumContentType{
JSON,
CSV,
XML
}

5、最后用客户端调用,直接根据类型调用对应的解析器,没有了switch case

@Service
publicclassClient{
privateParserFactoryparserFactory;
@Autowired
publicClient(ParserFactoryparserFactory){
this.parserFactory=parserFactory;
}
publicListgetAll(ContentTypecontentType){
..
//关键点,直接根据类型获取
returnparserFactory
.getParser(contentType)
.parse(reader);
}
..
}

嘿嘿,我们已经成功地实现了我们的目标。现在再加新的类型,我们只要扩展添加新的解析器就行,再也不用修改客户端了,满足开闭原则。

如果你觉得Bean的名称直接使用类型怪怪的,这边可以建议你按照下面的方式来。

publicenumContentType{
JSON(TypeConstants.JSON_PARSER),
CSV(TypeConstants.CSV_PARSER),
XML(TypeConstants.XML_PARSER);
privatefinalStringparserName;
ContentType(StringparserName){
this.parserName=parserName;
}

@Override
publicStringtoString(){
returnthis.parserName;
}
publicinterfaceTypeConstants{

StringCSV_PARSER="csvParser";
StringJSON_PARSER="jsonParser";
StringXML_PARSER="xmlParser";
}
}

@Component(TypeConstants.CSV_PARSER)
publicclassCSVParserimplementsParser{..}
@Component(TypeConstants.JSON_PARSER)
publicclassJSONParserimplementsParser{..}
@Component(TypeConstants.XML_PARSER)
publicclassXMLParserimplementsParser{..}

剖析Service Locator Pattern

通过前面的例子,想必大家基本知道服务定位器模式如何使用了吧,现在我们深入剖析下。

服务定位器模式消除了客户端对具体实现的依赖。以下引自Martin Fowler的文章总结了核心思想:“服务定位器背后的基本思想是拥有一个知道如何获取应用程序可能需要的所有服务的对象。因此,此应用程序的服务定位器将有一个在需要时返回“服务”的方法。”

8e123e42-af58-11ee-8b88-92fbcf53809c.png

Spring的ServiceLocatorFactoryBean实现了FactoryBean接口,创建了Service Factory服务工厂Bean。

总结

我们通过使用服务定位器模式实现了一种扩展 Spring 控制反转的绝妙方法。它帮助我们解决了依赖注入未提供最佳解决方案的用例。也就是说,依赖注入仍然是首选,并且在大多数情况下不应使用服务定位器来替代依赖注入。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    8496

    浏览量

    150826
  • 文件
    +关注

    关注

    1

    文章

    561

    浏览量

    24695
  • spring
    +关注

    关注

    0

    文章

    338

    浏览量

    14308
  • JSON
    +关注

    关注

    0

    文章

    117

    浏览量

    6940

原文标题:Spring项目中用了这种模式,经理对我刮目相看

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    java spring教程

    Spring核心概念介绍控制反转(IOC)依赖注入(DI)集合对象注入等Bean的管理BeanFactoryApplicationContextSpring 在web中的使用
    发表于 09-11 11:09

    什么是java spring

    通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反
    发表于 09-11 11:16

    Spring工作原理

    核心就是AOP这个就是面向切面编程,可以为某类对象 进行监督和控制(也就是在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对个模块扩充的功能。这些都是通过配置类达到的。
    发表于 07-10 07:41

    Spring笔记分享

    框架:高度抽取,可重用代码的一种设计高度的通用性多个可重用模块的集合,形成某个领域的整体解决方案Spring => 容器框架包含并管理应用对象的生命周期IOC和SOP容器框架容器 =>
    发表于 11-04 07:51

    启动Spring Boot项目应用的三种方法

    分别对这三启动方法做简单的介绍。第一种、IDEA编辑器启动。在我们开发过程中,用IDEA编辑器启动的方式最常见最推荐的启动方式。我们在项目中找到我们的启动文件,鼠标右击run启动文件即可。如下图所示
    发表于 01-14 17:33

    请问如何去实现一种按键控制电机的正反转

    如何去实现一种按键控制电机的正反转?按键控制电机的功能是什么?按键控制电机的接线方法有哪些?
    发表于 06-29 07:09

    spring教程ppt

    主要内容Spring 概述Spring 整体结构Spring实例Spring核心概念介绍控制反转
    发表于 09-11 11:00 138次下载
    <b class='flag-5'>spring</b>教程ppt

    一种金融系统专用ETL工具的研究与实现

    实现了一种基于Spring框架的商业银行专用ETL程序。该程序利用Spring框架的控制反转技术,基于Ibatis的数据访问对象技术和
    发表于 04-13 09:04 24次下载

    一种防止相间短路的电动机正反转控制

    一种防止相间短路的电动机正反转控制
    发表于 10-09 22:30 536次阅读
    另<b class='flag-5'>一种</b>防止相间短路的电动机正<b class='flag-5'>反转</b><b class='flag-5'>控制</b>

    一种防止相间短路的正反转控制电路图

    一种防止相间短路的正反转控制
    发表于 03-03 12:49 1038次阅读
    另<b class='flag-5'>一种</b>防止相间短路的正<b class='flag-5'>反转</b><b class='flag-5'>控制</b>电路图

    Spring认证_什么是Spring GraphQL?

    数据整合 Spring GraphQL 支持使用 Querydsl 通过 Spring Data Querydsl 扩展 来获取数据。Querydsl 提供了一种灵活但类型安全的
    的头像 发表于 08-09 11:31 585次阅读
    <b class='flag-5'>Spring</b>认证_什么是<b class='flag-5'>Spring</b> GraphQL?

    剖析Spring中最常用的扩展点(上)

    我们说到spring,可能第个想到的是 `IOC`(控制反转) 和 `AOP`(面向切面编程)。 没错,它们是
    的头像 发表于 02-15 16:06 719次阅读
    剖析<b class='flag-5'>Spring</b>中最常用的<b class='flag-5'>扩展</b>点(上)

    剖析Spring中最常用的扩展点(中)

    我们说到spring,可能第个想到的是 `IOC`(控制反转) 和 `AOP`(面向切面编程)。 没错,它们是
    的头像 发表于 02-15 16:06 486次阅读
    剖析<b class='flag-5'>Spring</b>中最常用的<b class='flag-5'>扩展</b>点(中)

    剖析Spring中最常用的扩展点(下)

    我们说到spring,可能第个想到的是 `IOC`(控制反转) 和 `AOP`(面向切面编程)。 没错,它们是
    的头像 发表于 02-15 16:07 435次阅读

    基于spring的SPI扩展机制是如何实现的?

    基本上,你说是基于 spring 的 SPI 扩展机制,再把spring.factories文件和EnableAutoConfiguration提
    的头像 发表于 03-07 09:17 1003次阅读