源码已经上传,有需要可在资源下载。在分布式day01的基础上,本节的新增内容主要是注册服务并独立运行,
首先在distributed文件夹下创建registry文件夹并在其下分别创建client.go,registration.go和server.go文件。
1、client.go
package registry
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func RegisterService(r Registration)error {
buf := new(bytes.Buffer)
enc := json.NewEncoder(buf)
err :=enc.Encode(r)
if err!=nil{
return err
}
res,err := http.Post(ServiceURL,"application/json",buf)
if err !=nil{
return err
}
if res.StatusCode!=http.StatusOK{
return fmt.Errorf("Failed to register")
}
return nil
}
主要用于客户端的注册服务,其中创建Post请求向注册地址即ServiceURL请求注册服务
2、registration.go
package registry
type Registration struct {
ServiceName ServiceName
ServiceURL string
}
type ServiceName string
const(
LogService = ServiceName("LogService")
)
创建注册信息结构体包括服务名服务地址
3、server.go
package registry
import (
"encoding/json"
"log"
"net/http"
"sync"
)
const ServerPort =":3000"
const ServiceURL = "http://localhost"+ServerPort+"/services"
type registry struct {
registrations []Registration//已经注册的服务
mutex *sync.Mutex//因为集合动态变化且可能并发访问为保证线程安全则加互斥锁
}
func (r *registry)add(reg Registration)error {
r.mutex.Lock()
r.registrations = append(r.registrations,reg)
r.mutex.Unlock()
return nil
}
//注册的服务集群
var reg = registry{
registrations: make([]Registration,0),
mutex: new(sync.Mutex),
}
type RegistryService struct {}//让其成为一个Handle
func (s RegistryService)ServeHTTP(w http.ResponseWriter,r *http.Request) {
log.Println("Request received")
switch r.Method {
case http.MethodPost:
dec := json.NewDecoder(r.Body)
var r Registration
err := dec.Decode(&r)
if err!=nil{
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Add service:%v with URL %v\n",r.ServiceName,r.ServiceURL)
err = reg.add(r)
if err!=nil{
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
用于将请求注册的服务加入注册服务集群中,此时的RegistryService因为实现了ServeHTTP接口,故成为了一个Handle,当请求为 //访问该地址后,启动RegistryService使其成为一个handle,如下,当请求为/services时,RegistryService便会将服务信息添加到注册集群中
http.Handle("/services",®istry.RegistryService{})
在cmd包下创建如下目录
main.go的内容如下
package main
import (
"context"
"distributed/registry"
"fmt"
"log"
"net/http"
)
//注册服务
func main() {
//访问该地址后,启动RegistryService使其称为一个handle
http.Handle("/services",®istry.RegistryService{})
//创建上下文和取消上下文
ctx,cancle :=context.WithCancel(context.Background())
//创建http.Server变量
var srv http.Server
//服务端口
srv.Addr = registry.ServerPort
go func() {
//启动服务是否成功,日志记录
log.Println(srv.ListenAndServe())
//结束线程
cancle()
}()
go func(){
fmt.Println("Registry service started.Press any key to stop.")
var s string
fmt.Scanln(&s)
srv.Shutdown(ctx)
cancle()
}()
<-ctx.Done()
fmt.Println("shutting down registy service")
}
其中ctx的作用,个人认为是退出服务的条件,即让<-ctx.Done不再阻塞,即可退出。
参数做如下修改
其中先执行注册服务,再执行日志服务
测试工具Postman
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)