# 寫一個Go服務
這是go-micro入門指南。
如果您首先喜歡更高級別的工具包概覽,請查看介紹性博客文章https://micro.mu/blog/2016/03/20/micro.html。
## 寫一個服務
頂級[服務接口](https://godoc.org/github.com/micro/go-micro#Service)是構建服務的主要組件。它將Go Micro的所有底層軟件包整合到一個簡單的接口中。
```
type Service interface {
Init(...Option)
Options() Options
Client() client.Client
Server() server.Server
Run() error
String() string
}
```
### 1.初始化
像使用`micro.NewService`一樣創建一個服務。
```
import "github.com/micro/go-micro"
service := micro.NewService()
```
選項可以在創建過程中傳入。
```
service := micro.NewService(
micro.Name("greeter"),
micro.Version("latest"),
)
```
所有可用的選項可以在[這里](https://godoc.org/github.com/micro/go-micro#Option)找到。
Go Micro還提供了使用`micro.Flags`設置命令行標志的方法。
```
import (
"github.com/micro/cli"
"github.com/micro/go-micro"
)
service := micro.NewService(
micro.Flags(
cli.StringFlag{
Name: "environment",
Usage: "The environment",
},
)
)
```
解析標志使用`service.Init`。另外訪問標志使用`micro.Action`選項。
```
service.Init(
micro.Action(func(c *cli.Context) {
env := c.StringFlag("environment")
if len(env) > 0 {
fmt.Println("Environment set to", env)
}
}),
)
```
Go Micro提供了預定義的標志,如果調用`service.Init`,它將被設置和解析。看到[這里](https://godoc.org/github.com/micro/go-micro/cmd#pkg-variables)的所有標志
### 2.定義API
我們使用protobuf文件來定義服務API接口。這是一種非常方便的方式來嚴格定義API并為服務器和客戶端提供具體的類型。
這是一個示例定義。
greeter.proto
```
syntax = "proto3";
service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string greeting = 2;
}
```
在這里,我們定義了一個名為Greeter的服務處理程序,其中的方法Hello使用參數`HelloRequest`類型并返回`HelloResponse`。
### 3.生成API接口
我們使用protoc和protoc-gen-go為這個定義生成具體的go實現。
Go-micro使用代碼生成來提供客戶端樁方法來減少代碼編寫,就像gRPC一樣。這是通過一個protobuf插件完成的,它需要一個[golang/protobuf](https://github.com/golang/protobuf)分支,可以在這里找到[github.com/micro/protobuf](https://micro.mu/docs/github.com/micro/protobuf)。
```
go get github.com/micro/protobuf/{proto,protoc-gen-go}
protoc --go_out=plugins=micro:. greeter.proto
```
生成的類型現在可以在請求時在服務器或客戶端的處理程序中導入和使用。
這是生成代碼的一部分。
```
type HelloRequest struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}
type HelloResponse struct {
Greeting string `protobuf:"bytes,2,opt,name=greeting" json:"greeting,omitempty"`
}
// Client API for Greeter service
type GreeterClient interface {
Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error)
}
type greeterClient struct {
c client.Client
serviceName string
}
func NewGreeterClient(serviceName string, c client.Client) GreeterClient {
if c == nil {
c = client.NewClient()
}
if len(serviceName) == 0 {
serviceName = "greeter"
}
return &greeterClient{
c: c,
serviceName: serviceName,
}
}
func (c *greeterClient) Hello(ctx context.Context, in *HelloRequest, opts ...client.CallOption) (*HelloResponse, error) {
req := c.c.NewRequest(c.serviceName, "Greeter.Hello", in)
out := new(HelloResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Greeter service
type GreeterHandler interface {
Hello(context.Context, *HelloRequest, *HelloResponse) error
}
func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler) {
s.Handle(s.NewHandler(&Greeter{hdlr}))
}
```
### 4.實現處理程序
服務器需要注冊處理程序來處理請求。處理程序是具有符合簽名
```
func(ctx context.Context, req interface{}, rsp interface{}) error
```
錯誤的公共方法的公共類型。正如你在上面看到的,Greeter接口的處理器簽名看起來像這樣。
```
type GreeterHandler interface {
Hello(context.Context, *HelloRequest, *HelloResponse) error
}
```
以下是Greeter處理程序的實現。
```
import proto "github.com/micro/examples/service/proto"
type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
rsp.Greeting = "Hello " + req.Name
return nil
}
```
該處理程序在您的服務中注冊很像一個http.Handler。
```
service := micro.NewService(
micro.Name("greeter"),
)
proto.RegisterGreeterHandler(service.Server(), new(Greeter))
```
您也可以創建一個雙向流媒體處理程序。
### 5. 運行服務
該服務可以通過調用`server.Run`來運行。這導致服務綁定到配置中的地址(默認為第一個RFC1918接口和隨機端口)并偵聽請求。
這將另外注冊服務注冊表啟動和注銷時發出一個kill信號。
```
if err := service.Run(); err != nil {
log.Fatal(err)
}
```
### 6. 完整的服務
greeter.go
```
package main
import (
"log"
"github.com/micro/go-micro"
proto "github.com/micro/examples/service/proto"
"golang.org/x/net/context"
)
type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
rsp.Greeting = "Hello " + req.Name
return nil
}
func main() {
service := micro.NewService(
micro.Name("greeter"),
micro.Version("latest"),
)
service.Init()
proto.RegisterGreeterHandler(service.Server(), new(Greeter))
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
```
注意:服務發現機制將需要運行,以便服務可以注冊被客戶和其他服務發現。快速入門就在[這里](https://github.com/micro/go-micro#getting-started)。
## 寫一個客戶端
[客戶端](https://godoc.org/github.com/micro/go-micro/client)軟件包用于查詢服務。在創建服務時,將包含一個與服務器使用的初始化包相匹配的客戶端。
查詢以上服務如下所示。
```
// create the greeter client using the service name and client
greeter := proto.NewGreeterClient("greeter", service.Client())
// request the Hello method on the Greeter handler
rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{
Name: "John",
})
if err != nil {
fmt.Println(err)
return
}
fmt.Println(rsp.Greeter)
```
`proto.NewGreeterClient`獲取服務名稱和用于發出請求的客戶端。
完整的例子可以在[go-micro/examples/service](https://github.com/micro/examples/tree/master/service)中找到。