go-kit是一个分布式的开发工具集,在大型的组织(业务)中可以用来构建微服务,其解决了分布式系统中大多数常见问题,因此,使用者可以将精力集中在业务逻辑上
首先我们要明白,go-kit不是一个框架,他只是一个工具集,他里面有用来帮助我们实现微服务的一些工具包,所以他并不想SpringBoot那样能帮我们直接把框架搭好,我们只要在项目框架上直接写我们的代码就好了。
但是他跟SpringBoot又有相似的地方,比如MVC和go-kit的三层架构。
微服务
要了解go-kit我们首先要知道什么事微服务,毕竟go-kit是为了更方便的实现微服务而存在的。
维基百科:
微服务(英语:Microservices)是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small BuildingBlocks) 为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关(Language-Independent/Language agnostic)的API集相互通信。
我们可以知道,微服务就是一个大项目中的一个小功能块,并且这个功能块可以不计语言差别的和其他功能模块通过API进行通讯和结合。
所以通过微服务,我们可以知道,工作之间的接触就可以完全是,这个模块我要输入什么得到什么输出,有另外一个人那里沟通好,其他的就不用管了,让他一个人安安静静的开发就好了,等他做完我按照这个格式去取我想要的结果就好了。
go-kit三层结构
go-kit和SSM中的MVC一样也有三层结构endpoint,service, transport,通过这三层结构来实现,接收一个请求,然后返回一个结果。
-
Transport
Transport处于该微服务的最上层,主要负责于HTTP, gRPC,thrift等相关的逻辑,负责解析请求,并且调用endpoint来处理请求 -
Endpoint
endpoint属于客户端和服务端的转接器,他定义了request和response的格式,上层给Transport调用来处理请求,下层链接Service将Service所返回的结果转换成request需要的格式 -
Service
最底下的我们这个模块所需要实现的功能了
下面我们通过一个简单的例子来详细了解一下。我们得到的需求是,传入一个用户id,然后返回该id对应的姓名。
go-kit实例
首先创建我们的基本框架,因为是入门级项目,我们就严格按照go-kit的三层结构来设计我们的框架。
Service
最简单的,我们先实现我们最基本的需求解决方法吧,这里最重要的就是GetName接口以及他的实现,这一层比较简单
package service
type IUserService interface {
GetName(userId int) string
}
type UserService struct {
}
func (receiver UserService) GetName(userId int) string {
if userId == 101 {
return "calvin"
}
return "guest"
}
EndPoint
endpoint的作用最简单的,对于一个从上层Transport传入的request,我们返回一个response,也就是可以写成这样
// 这定义了一个类似接口的方法Endpoint
type EndPoint func(request) response
写得再详细一点就是
type EndPoint func(ctx context.Context, request interface{}) (response interface{}, err error)
// 所以endpoint主要的功能其实主要是返回一个函数,但是对于我们来说,要将底层的Service封装进这个函数中去,所以应该更详细的写成
func GetEndPoint(service Service) endpoint.Endpoint{
return func(ctx context.Context, request interface{})(response interface{}, err error){
// 实现算法
}
}
其实context和reques interface以及response interface不了解的不重要,我们现在知道这是固定的格式就好了,以后有更深入的需要和了解再去学习。
大概了解了endpoint的格式之后我们就来写自己的endpoint的方法
package endpoint
import (
"context"
"github.com/go-kit/kit/endpoint"
"go-kit-test/service"
)
// 定义request输入的格式 uid:xx json格式
type UserRequest struct{
Uid int `json: "uid"`
}
// 定义response输出格式 result:xx json格式
type UserResponse struct{
Result string `json: "result" `
}
// interface{} 的意思是request和response输入和输出无论什么格式都可以
func GetUserEndPonint(userService service.IUserService) endpoint.Endpoint{
return func(ctx context.Context, request interface{})(response interface{},err error){
r:= request.(UserRequest)
result := userService.GetName(r.Uid)
return UserResponse{Result: result}, nil
}
}
r:=request.(UserRequest)r.Uid
Transport
package transport
import (
"context"
"encoding/json"
"errors"
"go-kit-test/endpoint"
"net/http"
"strconv"
)
//这一块为核心实现,从一个http请求,request得到url,然后通过解析url得到我们所需要的uid,然后将其转化成endpoint中定义好的UserRequest模式返回
func DecodeUserRequest(ctx context.Context, r *http.Request) (interface{}, error) {
if r.URL.Query().Get("uid") != "" {
uid, _ := strconv.Atoi(r.URL.Query().Get("uid"))
return endpoint.UserRequest{Uid: uid}, nil
}
return nil, errors.New("参数错误")
}
//这个可以暂时不用管
func EncodeUserResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
// transport body to json
w.Header().Set("Content-type", "application/json")
return json.NewEncoder(w).Encode(response)
}
r:=request.(UserRequest)
其实最重要的,我们需要建一个main方法将endpoint+service这一部分,和transport组装起来
package main
import (
httpTransport "github.com/go-kit/kit/transport/http"
"go-kit-test/endpoint"
"go-kit-test/service"
"go-kit-test/transport"
"net/http"
)
func main() {
user := service.UserService{}
endPoint := endpoint.GetUserEndPoint(user)
// implement http.handler and encapsulate with endpoint
serverHandler := httpTransport.NewServer(endPoint, transport.DecodeUserRequest, transport.EncodeUserResponse)
// listen the port
_ = http.ListenAndServe(":8080", serverHandler)
}
serverHandler := httpTransport.NewServer(endPoint, transport.DecodeUserRequest, transport.EncodeUserResponse)DecodeUserRequestendPointListenAndServer127.0.0.1:8080
http://127.0.0.1:8080?uid=101