zoukankan      html  css  js  c++  java
  • 手把手带你使用 go-kit(基础篇)

    手把手带你使用 go-kit

    go-kit 是什么

    Go kit 是一个微服务工具包集合。利用它提供的额API和规范可以创建健壮、可维护性高的微服务体系

    Go-kit的三层架构

    1、Service 
    这里就是我们的业务类、接口等相关信息存放
    
    2、EndPoint
    定义Request、Response格式,并可以使用装饰器(闭包)包装函数,以此来实现各个中间件嵌套
    
    3、Transport
    主要负责与HTTP、gRPC、thrift等相关逻辑
    

    上面是 Go-kit 定义的架构模式 这里我们引入一个最简单的Demo

    // 项目结构
    -| Server
    ----| server.go
    -| EndPoint
    ----| endpoint.go
    -| Transport
    ----| Transport.go
    - main.go
    

    1.首先我们先写Server层业务类

    // Server/server.go
    package Server
    
    import "fmt"
    
    // server.go 实现业务
    
    // IServer 用于定义业务方法的接口
    type IServer interface {
    	// 这里只需要关注我 IServer 对业务所需要的方法即可
    	// 例如: 我这里要实现一个问候的方法 和一个 bye的方法 比较简单 传入一个名字 返回一个名字
    	Hello(name string) string
    	Bye(name string) string
    }
    
    // Server 用于实现上面定义的接口
    type Server struct {
    	// 根据业务需求填充结构体...
    }
    
    // 实现上方定义的业务方法
    
    func (s Server) Hello(name string) string {
    	return fmt.Sprintf("%s:Hello", name)
    }
    
    func (s Server) Bye(name string) string {
    	return fmt.Sprintf("%s:Bye", name)
    }
    

    2.接下来我们实现EndPoint中的内容

    // EndPoint/endpoint.go
    package EndPoint
    
    import (
    	"Songzhibin/go-kit-demo/v0/Server"
    	"context"
    	"github.com/go-kit/kit/endpoint"
    )
    
    // endpoint.go 定义 Request、Response 格式, 并且可以使用闭包来实现各种中间件的嵌套
    // 这里了解 protobuf 的比较好理解点
    // 就是声明 接收数据和响应数据的结构体 并通过构造函数创建 在创建的过程当然可以使用闭包来进行一些你想要的操作啦
    
    // 这里根据我们Demo来创建一个响应和请求
    // 当然你想怎么创建怎么创建 也可以共用 这里我分开写 便于大家看的清楚
    
    // Hello 业务使用的请求和响应格式
    // HelloRequest 请求格式
    type HelloRequest struct {
    	Name string `json:"name"`
    }
    
    // HelloResponse 响应格式
    type HelloResponse struct {
    	Reply string `json:"reply"`
    }
    
    // Bye 业务使用的请求和响应格式
    // ByeRequest 请求格式
    type ByeRequest struct {
    	Name string `json:"name"`
    }
    
    // ByeResponse 响应格式
    type ByeResponse struct {
    	Reply string `json:"reply"`
    }
    
    // ------------ 当然 也可以通用的写 ----------
    // Request 请求格式
    type Request struct {
    	Name string `json:"name"`
    }
    
    // Response 响应格式
    type Response struct {
    	Reply string `json:"reply"`
    }
    
    // 这里创建构造函数 hello方法的业务处理
    // MakeServerEndPointHello 创建关于业务的构造函数
    // 传入 Server/server.go 定义的相关业务接口
    // 返回 go-kit/endpoint.Endpoint (实际上就是一个函数签名)
    func MakeServerEndPointHello(s Server.IServer) endpoint.Endpoint {
    	// 这里使用闭包,可以在这里做一些中间件业务的处理
    	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    		// request 是在对应请求来时传入的参数(这里的request 实际上是等下我们要将的Transport中一个decode函数中处理获得的参数)
    		// 这里进行以下断言
    		r, ok := request.(HelloRequest)
    		if !ok {
    			return Response{}, nil
    		}
    		// 这里实际上就是调用我们在Server/server.go中定义的业务逻辑
    		// 我们拿到了 Request.Name 那么我们就可以调用我们的业务 Server.IServer 中的方法来处理这个数据并返回
    		// 具体的业务逻辑具体定义....
    		return HelloResponse{Reply: s.Hello(r.Name)}, nil
    		// response 这里返回的response 可以返回任意的 不过根据规范是要返回我们刚才定义好的返回对象
    
    	}
    }
    
    // 这里创建构造函数 Bye方法的业务处理
    // MakeServerEndPointBye 创建关于业务的构造函数
    // 传入 Server/server.go 定义的相关业务接口
    // 返回 go-kit/endpoint.Endpoint (实际上就是一个函数签名)
    func MakeServerEndPointBye(s Server.IServer) endpoint.Endpoint {
    	// 这里使用闭包,可以在这里做一些中间件业务的处理
    	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    		// request 是在对应请求来时传入的参数(这里的request 实际上是等下我们要将的Transport中一个decode函数中处理获得的参数)
    		// 这里进行以下断言
    		r, ok := request.(ByeRequest)
    		if !ok {
    			return Response{}, nil
    		}
    		// 这里实际上就是调用我们在Server/server.go中定义的业务逻辑
    		// 我们拿到了 Request.Name 那么我们就可以调用我们的业务 Server.IServer 中的方法来处理这个数据并返回
    		// 具体的业务逻辑具体定义....
    		return ByeResponse{Reply: s.Bye(r.Name)}, nil
    		// response 这里返回的response 可以返回任意的 不过根据规范是要返回我们刚才定义好的返回对象
    	}
    }
    

    3.最后我们实现重中之重的 Transport

    // Transport/transport.go
    package Transport
    
    import (
    	"Songzhibin/go-kit-demo/v0/EndPoint"
    	"context"
    	"encoding/json"
    	"errors"
    	"net/http"
    )
    
    // Transport/transport.go 主要负责HTTP、gRpc、thrift等相关的逻辑
    
    // 这里有两个关键函数
    // DecodeRequest & EncodeResponse 函数签名是固定的哟
    // func DecodeRequest(c context.Context, request *http.Request) (interface{}, error)
    // func EncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error
    
    // HelloDecodeRequest 解码 后封装至 EndPoint中定义的 Request格式中
    func HelloDecodeRequest(c context.Context, request *http.Request) (interface{}, error) {
    	// 这里主要就是通过 request 拿到对应的参数构造成在 EndPoint中定义的 Request结构体即可
    
    	name := request.URL.Query().Get("name")
    	if name == "" {
    		return nil, errors.New("无效参数")
    	}
    	// 这里返回的是
    	return EndPoint.HelloRequest{Name: name}, nil
    }
    
    // HelloEncodeResponse 通过响应封装成 EndPoint中定义的 Response结构体即可
    func HelloEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
    	// 这里将Response返回成有效的json格式给http
    
    	// 设置请求头信息
    	w.Header().Set("Content-Type", "application/json;charset=utf-8")
    	// 使用内置json包转换
    	return json.NewEncoder(w).Encode(response)
    }
    
    // ByeDecodeRequest 解码 后封装至 EndPoint中定义的 Request格式中
    func ByeDecodeRequest(c context.Context, request *http.Request) (interface{}, error) {
    	// 这里主要就是通过 request 拿到对应的参数构造成在 EndPoint中定义的 Request结构体即可
    
    	name := request.URL.Query().Get("name")
    	if name == "" {
    		return nil, errors.New("无效参数")
    	}
    	// 这里返回的是
    	return EndPoint.ByeRequest{Name: name}, nil
    }
    
    // sayEncodeResponse 通过响应封装成 EndPoint中定义的 Response结构体即可
    func sayEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
    	// 这里将Response返回成有效的json格式给http
    
    	// 设置请求头信息
    	w.Header().Set("Content-Type", "application/json;charset=utf-8")
    	// 使用内置json包转换
    	return json.NewEncoder(w).Encode(response)
    }
    

    4.服务启动

    // main.go
    package main
    
    import (
    	EndPoint1 "Songzhibin/go-kit-demo/v0/EndPoint"
    	"Songzhibin/go-kit-demo/v0/Server"
    	"Songzhibin/go-kit-demo/v0/Transport"
    	httpTransport "github.com/go-kit/kit/transport/http"
    	"net/http"
    )
    
    // 服务发布
    
    func main() {
    	// 1.先创建我们最开始定义的Server/server.go
    	s := Server.Server{}
    
    	// 2.在用EndPoint/endpoint.go 创建业务服务
    	hello := EndPoint1.MakeServerEndPointHello(s)
    	Bye := EndPoint1.MakeServerEndPointBye(s)
    
    	// 3.使用 kit 创建 handler
    	// 固定格式
    	// 传入 业务服务 以及 定义的 加密解密方法
    	helloServer := httpTransport.NewServer(hello, Transport.HelloDecodeRequest, Transport.HelloEncodeResponse)
    	sayServer := httpTransport.NewServer(Bye, Transport.ByeDecodeRequest, Transport.ByeEncodeResponse)
    
    	// 使用http包启动服务
    	go http.ListenAndServe("0.0.0.0:8000", helloServer)
    
    	go http.ListenAndServe("0.0.0.0:8001", sayServer)
    	select {}
    }
    

    我们尝试运行一下

    Songzhibin
  • 相关阅读:
    浮点数
    2020.07.13
    2020.07.07
    2020.07.06
    剑指offer(三)
    剑指offer(二)
    剑指offer
    堆排序
    归并排序
    希尔排序
  • 原文地址:https://www.cnblogs.com/binHome/p/13927942.html
Copyright © 2011-2022 走看看