系统设计:你的service要用Dependency Injection吗?

简介: 系统设计:你的service要用Dependency Injection吗?

正文


我最近在给一个Go service升级重构framework。我和一个朋友提了下,他点评到,搞这种基础升级,就是悟道啊,类似于《禅与摩托车维修艺术》。


image.png


他这个说法挺有道理的,大家平时写业务代码,更多是站在地面想着怎么快速完成目标。只有趁升级的时候,才有空飞在1000公里天上,想想为啥要这么设计的哲学问题。


今天就给大家介绍一个重要的基本设计原则:Dependency Injection。这个设计模式在复杂的业务service非常有用,没有它,每次改一个模块的初始化接口,你都要把用到这个模块的代码都改一遍,非常麻烦。


今天很多主流的开源framework都用到了它,比如:


  • Guice: Google 维护的一个基于Java的 lightweight dependency injection framework
  • Fx: Uber 维护的一个基于Go的dependency injection framework
  • AngularJS: Google 维护的基于JavaScript的前端 framework
  • Wire: Google维护的Compile-time Dependency Injection for Go


什么是Dependency Injection?


这个翻译成中文叫做依赖注入,用大白话解释就是即插即用。


举个例子,假设你的service里面有个模块A叫“笔记本”,它有个依赖叫“耳机”,用了这个设计原则,你需要听音乐,只用插”耳机“就可以了。后端service中常见的“耳机”依赖有哪些?比如Logging,输出Metrics等。


image.png

下面的代码是用 Dependency Injection 创建模块A的伪代码:


func CreateLaptopService() *LaptopService {
  panic(wire.Build(
    wire.Struct(new(Logger), "*"),
    NewHttpClient,
    NewHeadphoneService,
  ))
}


不用这个原则,有什么后果?


你需要自己搞一堆耳机的原材料,然后自己组装配置。模块A需要耳机的时候,手动装一遍,模块B需要耳机的时候,再手动装一遍。


image.png

下面是不用Dependency Injection,创建模块A的伪代码:


func CreateLaptopService() *LaptopService {
  logger := &Logger{}
  headphone := &Headphone{}
  client := NewHttpClient(logger)
  return NewLaptopService(logger,client,headphone)
}


如果service很简单,还可以忍受。但是在业务很复杂时,项目里有上百个依赖的时候就更痛苦了。每次配置”耳机“,你都需要手动把所有模块的接口配置一遍。


下面是不用Dependency Injection,再创建模块B的伪代码:


func CreateDesktopService() *DesktopService {
  logger := &Logger{}
  headphone := &Headphone{}
  client := NewHttpClient(logger)
  cdDisk := &CdDisk{}
  cdDrive := &CdDrive{cdDisk}
  headphone := &Headphone{}
  return NewLaptopService(logger, client, headphone, cdDrive)
}


优点一:减少依赖关系、方便重复使用


有了Dependency Injection,每次配置时,模块A和模块B都是连接到同一个设置的耳机,你只要组装一次耳机。即使有100个模块都需要用耳机,你也只需要组装一次。


image.png


优点二:提高可维护性


而对于更复杂的场景,模块B依赖于一个”CD机“,而”CD机“又需要一个”CD碟片“。如果有100个类似的模块都有”CD机“,而你需要做的只是更改”CD机”里的CD碟片,有了Dependency Injection,你也可以省去在“电子厂”里面翻找所有”CD机“的时间,只需要换一张”CD碟片“。


优点三:简化测试流程


每次升级时,只需要测试”耳机“本身的性能,测试不需要和使用”耳机“的代码有任何关联。


总结


最后,划一下重点,Dependency Injection适用的场景,是复杂的大型系统,有很多个服务相互依赖的情况。它能够避免一些重复劳动带来的小错误,提高生产力。如果是一个人写的小玩具,那杀鸡就不用牛刀啦。

相关文章
|
3月前
|
Java Spring
【Azure Service Bus】使用Spring Cloud integration示例代码,为多个 Service Bus的连接使用 ConnectionString 方式
【Azure Service Bus】使用Spring Cloud integration示例代码,为多个 Service Bus的连接使用 ConnectionString 方式
|
3月前
|
Java Spring
【Azure 服务总线】Spring Cloud 的应用 使用Service Bus 引起 org.springframework.beans.BeanInstantiationException 异常,无法启动
【Azure 服务总线】Spring Cloud 的应用 使用Service Bus 引起 org.springframework.beans.BeanInstantiationException 异常,无法启动
|
6月前
|
前端开发 Java Spring
使用Spring Boot集成Shiro时出现了无法注入Service的问题
使用Spring Boot集成Shiro时出现了无法注入Service的问题
107 0
|
6月前
|
XML SQL Java
springboot 项目启动报Has been loaded by XML or SqlProvider, ignoring the injection of the SQL的错误的解决方案
springboot 项目启动报Has been loaded by XML or SqlProvider, ignoring the injection of the SQL的错误的解决方案
834 0
|
Java Linux Spring
每日一博 - Spring Boot Application as a Service
每日一博 - Spring Boot Application as a Service
96 0
|
存储 安全 算法
Spring security (一)架构框架-Component、Service、Filter分析
  想要深入spring security的authentication (身份验证)和access-control(访问权限控制)工作流程,必须清楚spring security的主要技术点包括关键接口、类以及抽象类如何协同工作进行authentication 和access-control的实现。
335 0
|
JavaScript Java Linux
在Pivotal Web Service上发布Spring Boot应用
在Pivotal Web Service上发布Spring Boot应用
205 0
在Pivotal Web Service上发布Spring Boot应用
|
Java Maven Spring
spring cloud架构 - HongHu common-service 项目构建过程
spring cloud架构 - HongHu common-service 项目构建过程 Maven(项目构建)、Spring Boot、Spring Cloud、微服务概念、去中心化思想、分布式等,针对于common-service的顶级项目,这里我们主要使用Maven来构建,闲话少说,我们直接上代码是最直观的。
1355 0
|
Java Spring 测试技术
SpringBoot开发案例之整合Quartz注入Service
前段时间做了一个基于SpringBoot和Quartz任务管理系统(脚手架而已),很多功能不是特别完善,由于工作原因,断断续续一直在更新中,码云上有个小伙伴提问说:Job中service自动注入报错怎么解决?正好之间做的项目中有使用到注入相关的功能,顺便也集成进去。
4749 0