依赖注入是什么?Go是如何实现依赖注入的?
- 什么是依赖注入
- 依赖注入的好处
- Go的依赖注入-wire
依赖注入是什么?
第一次听到这个词的时候我是一脸懵逼的,很拗口有没有,可能很多学过spring的同学觉得这是很基础很好理解的知识,但因为我之前没学过Java和spring,所以第一次接触这个词的时候是很懵的。
依赖注入,英文名dependency injection,简称DI。依赖两个字很好理解,在软件设计上,从架构模块到函数方法都存在大大小小的依赖关系。
比如说在new A 之前需要先new B ,A依赖于B,这时候我们就可以说B是A的依赖,A控制B,AB之间存在着耦合的关系,而代码设计思想是最好可以做到松耦合。如果某一天B需要改造那么A也需要跟着改造。这是一个依赖你可以觉得没问题,但如果是A->B->C->D->E->F之间存在一连串的依赖关系,那么改造起来就会十分麻烦。
这个时候就需要一种东西来解开他们之间的强耦合,怎么解耦呢,只能借助第三方力量了,我们把A对B的控制权交给第三方,这种思想就称为控制反转(IOC Inversion Of Control),这个第三方称为IOC容器。而IOC容器要做的事情就是new一个B出来,然后把这个B的实例注入到A里面去,然后A就可以正常的使用基于B的方法了,这个过程被称为依赖项注入,而基于IOC的这种方法就叫做依赖注入。
依赖注入的好处
明白了依赖注入的思想,应该也就明白了其带来的最大好处——解耦。
而解耦又能带来更多的好处:代码扩展性增强,代码的可维护性增强,更容易进行单元测试等等。
那么依赖注入如何实现呢?
Java中有以下几种方式:
- setter方法注入:实现特定属性的public set方法,来让外部容器调用传入所依赖类型的对象。
- 基于接口的注入:实现特定接口以供外部容器注入所依赖类型的对象。
- 基于构造函数的注入:实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。
- 基于注解的注入:在代码里加上特定的关键字实现注入。
注解是最常见的方式,它像注释一样不被当做代码来执行,而是专门供别人阅读。但注释的读者完全是人类,而注解的主要读者除了人类之外还有框架或预编译器。
Go依赖注入-wire
wire就是一种基于注解的依赖注入方式。wire
是 Google 开源的一个依赖注入工具,我们只需要在一个特殊的go
文件中告诉wire
类型之间的依赖关系,它会自动帮我们生成代码,帮助我们创建指定类型的对象,并组装它的依赖。
wire
有两个基础概念,Provider
(构造器)和Injector
(注入器)。
通过提供provider
函数,让wire
知道如何产生这些依赖对象。wire
根据我们定义的injector
函数签名,生成完整的injector
函数,injector
函数是最终我们需要的函数,它将按依赖顺序调用provider
。
wire
的要求很简单,新建一个wire.go
文件(文件名可以随意),创建我们的初始化函数。比如,我们要创建并初始化一个Mission
对象,我们就可以这样:
//+build wireinjectpackage mainimport "github.com/google/wire"func InitMission(name string) Mission {wire.Build(NewMonster, NewPlayer, NewMission)return Mission{}
}
可以看到第一行的注解:+build wireinject,表示这是一个注入器。+build
其实是 Go 语言的一个特性。类似 C/C++ 的条件编译,在执行go build
时可传入一些选项,根据这个选项决定某些文件是否编译。wire
工具只会处理有wireinject
的文件,所以我们的wire.go
文件要加上这个。
在函数中,我们调用wire.Build()
将创建Mission
所依赖的类型的构造器传进去。例如,需要调用NewMission()
创建Mission
类型,NewMission()
接受两个参数一个Monster
类型,一个Player
类型。Monster
类型对象需要调用NewMonster()
创建,Player
类型对象需要调用NewPlayer()
创建。所以NewMonster()
和NewPlayer()
我们也需要传给wire
。
写完wire.go文件之后执行wire命令,就会自动生成一个wire_gen.go文件。
// Code generated by Wire. DO NOT EDIT.//go:generate wire
//+build !wireinjectpackage main// Injectors from wire.go:func InitMission(name string) Mission {player := NewPlayer(name)monster := NewMonster()mission := NewMission(player, monster)return mission
}
可以看到wire自动帮我们生成了InitMission方法,此方法中依次初始化了player,monster和mission。之后在我们的main函数中就只需调用这个InitMission即可。
func main() {mission := InitMission("dj")mission.Start()
}
而在没用依赖注入之前,我们的代码是这样的:
func main() {monster := NewMonster()player := NewPlayer("dj")mission := NewMission(player, monster)mission.Start()
}
是不是简洁了很多。这里只有三个对象的初始化,如果是更多可能才会意识到依赖注入的好处。
比如:
wire.go文件:
// +build wireinject
// The build tag makes sure the stub is not built in the final build.package diimport ("github.com/google/wire"
)//go:generate kratos t wire
func InitApp() (*App, func(), error) {panic(wire.Build(dao.Provider, service.Provider, http.New, grpc.New, NewApp))
}实现文件:
//dao
var Provider = wire.NewSet(New, NewDB, NewRedis)
//service
var Provider = wire.NewSet(New, wire.Bind(new(pb.Server), new(*Service)))生成的wire_gen.go 文件:
func InitApp() (*App, func(), error) {redis, cleanup, err := dao.NewRedis()if err != nil {return nil, nil, err}db, cleanup2, err := dao.NewDB()if err != nil {cleanup()return nil, nil, err}daoDao, cleanup3, err := dao.New(redis, db)if err != nil {cleanup2()cleanup()return nil, nil, err}serviceService, cleanup4, err := service.New(daoDao)if err != nil {cleanup3()cleanup2()cleanup()return nil, nil, err}engine, err := http.New(serviceService)if err != nil {cleanup4()cleanup3()cleanup2()cleanup()return nil, nil, err}server, err := grpc.New(serviceService)if err != nil {cleanup4()cleanup3()cleanup2()cleanup()return nil, nil, err}app, cleanup5, err := NewApp(serviceService, engine, server)if err != nil {cleanup4()cleanup3()cleanup2()cleanup()return nil, nil, err}return app, func() {cleanup5()cleanup4()cleanup3()cleanup2()cleanup()}, nil
}
所以,依赖注入到底是什么?
封装解耦罢了。
依赖注入是什么?Go是如何实现依赖注入的?相关推荐
- 依赖注入及AOP简述(一)——“依赖”的概念 .
一.入门:依赖注入 作为一种全新的设计模式理念,"依赖注入"这个词汇在软件设计开发中已经是越来越耳熟能详了,而各种流行于开源社区的"依赖注入框架",也越来越多的 ...
- 利用抽象工厂创建DAO、利用依赖注入去除客户端对工厂的直接依赖、将有关Article的各种Servlet封装到一个Servlet中(通过BaseServlet进行
利用抽象工厂创建DAO.利用依赖注入去除客户端对工厂的直接依赖.将有关Article的各种Servlet全部封装到一个Servlet中(通过BaseServlet来进行ArticleServlet方法 ...
- 依赖注入及AOP简述(五)——依赖注入的方式 .
二.依赖注入的应用模式 前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想. 1. 依赖注入的方 ...
- go 依赖注入 哪个好_go与java的依赖注入实现的一些差异
go语言是一门开源的语言,我这里说开源,并不是指go的编译器等是开源,而是指go在机制上决定了当我们引入一个类库的时候,实质上是引入类库的源码. 纯go实现的类库.模块,基本是无法以编译后二进制的形式 ...
- laravel mysql注入_详解 Laravel 中的依赖注入和 IoC
Laravel 作为开发者,我们一直在尝试通过使用设计模式和尝试新的健壮型框架来寻找新的方式来编写设计良好且健壮的代码.在本篇文章中,我们将通过 Laravel 的 IoC 组件探索依赖注入设计模式, ...
- java手工注入bean_java相关:Spring中如何动态注入Bean实例教程
java相关:Spring中如何动态注入Bean实例教程 发布于 2020-3-8| 复制链接 摘记: 前言在Spring中提供了非常多的方式注入实例,但是由于在初始化顺序的不同,基于标注的注入方式, ...
- 【SQL注入技巧拓展】————4、高级SQL注入:混淆和绕过
[0×01] – 简介 大家好,这是一篇致力于文档化我们所从事的高级SQL注入技术的文章. 本文将要揭示能用于现实CMSs和WAFs程序中的高级绕过技术和混淆技术.文中所提到的SQL注入语句仅仅是一些 ...
- html避免js脚本注入,chrome浏览器拓展——js脚本拦截及注入
概要 该浏览器拓展插件是拥有为页面拦截和注入js功能的chrome浏览器扩展,可以拦截页面脚本.检索页面脚本文件.下载页面脚本文件.为页面注入js文件,以及为页面注入requirejs和require ...
- Spring循环依赖问题,Spring是如何解决循环依赖的?
文章目录 一.什么是循环依赖 1.代码实例 2.重要信息 二.源码分析 1.初始化Student 对Student中的ClassRoom进行Autowire操作 2.Student的自动注入Class ...
- 【Spring源码:循环依赖】一文弄懂Spring循环依赖
1. 什么是循坏依赖 很简单,其实就是互相依赖对方,比如,有一个A对象依赖了B对象,B对象又依赖了A对象. // A依赖了B public class A{private B b; }// B依赖了A ...
最新文章
- 背水一战 Windows 10 (40) - 控件(导航类): AppBar, CommandBar
- 赵立新主持机器人_《档案》第二任主持人赵立新:我是石凉接班人
- php中文网企业网站,闻名 PHP企业网站系统 weenCompany v5.3.0 简体中文 UTF8
- 如何把荣耀手机的计算机移动到桌面,华为荣耀怎么把天气预报设置到桌面
- Matlab repmat函数
- 重写慢日志解析程序,实现打印慢SQL信息及其所属数据库
- 探讨专线与家用宽带的区别
- Java中print、printf、println的区别(转载)
- C# 仿windows资源管理器
- 公交非接触IC卡读写器的应用设计
- HID热插拔后,设备状态改变,上位机自动识别
- 时光轴全新导购网站购物新体验
- 信号与系统(20)-拉普拉斯变换的性质
- excel入门/常用的技巧
- 微信小程序与uni-app的区别
- c语言程序设计第三版乌云高娃答案,C语言程序设计教学课件作者第3版乌云高娃补充习题及答案C语言程序设计教学课件作者第3版乌云高娃补充习题及答案第3章补充习题及答案课件.doc...
- 铁大部分风景图片及文字描述。。。。
- c8网络语言意思,老外常用的网络英文缩写
- Spring 官方文档彩蛋
- java注册用户代码_Java用户注册代码
热门文章
- Java细节:单等于号、双等于号、三等于号(js中才有)的作用及双等于号和equals(源码)的区别
- Nginx基于IP的访问控制
- 【LeetCode Python实现】 5473. 灯泡开关 IV(中等)
- E22 LoRa模块透传 定点传输 WOR模式测试与MicroPython应用
- 记录 ESIM 安装、使用过程中遇到的问题
- 编译时出现stripped of unavailable superclass
- linux oracle创建用户并授权
- Quartz简介及初始化
- CF-133A - HQ9+
- iOS之导航UINavigationController的使用(一)