Go语言微服务框架go-micro(入门)
Micro用于构建和管理分布式系统,是一个工具集,其中go-micro框架是对分布式系统的高度抽象,提供分布式系统开发的核心库,可插拔的架构,按需使用
简单示例
编写protobuf文件:
syntax = "proto3"; option go_package = ".;proto"; service Cap { rpc SayHello(SayRequest) returns (SayResponse) {} } message SayRequest { string message = 1; } message SayResponse { string answer = 1; }
生成代码:
$ protoc -I ./ --go_out=./proto --micro_out=./proto ./proto/hello.proto
编写服务端:
type CapServer struct{} func (c *CapServer) SayHello(ctx context.Context, req *proto.SayRequest, resp *proto.SayResponse) error { resp.Answer = "hello: " + req.Message return nil } func main() { service := micro.NewService(micro.Name("test.server")) // 创建新服务 service.Init() // 初始化方法 _ = proto.RegisterCapHandler(service.Server(), new(CapServer)) // 注册服务 if err := service.Run(); err != nil { fmt.Println(err) } }
客户端:
func main() { service := micro.NewService(micro.Name("test.client")) service.Init() client := proto.NewCapService("test.server", service.Client()) res, err := client.SayHello(context.TODO(), &proto.SayRequest{Message: "test"}) if err != nil { fmt.Println(err) } fmt.Println(res.Answer) }
目录搭建
使用docker的micro容器,创建一个micro目录:
$ sudo docker run --rm -v $(pwd):$(pwd) -w $(pwd) micro/micro new user
编写一个用户信息的服务
首先定义一个protobuf文件:
syntax = "proto3"; package go.micro.service.user; option go_package = ".;proto"; service User { rpc Register(UserRegisterRequest) returns (UserRegisterResponse) {} rpc Login(UserLoginRequest) returns (UserLoginResponse) {} rpc GetUserInfo(UserInfoRequest) returns (UserInfoResponse) {} } message UserInfoRequest { string user_name = 1; } message UserInfoResponse { int64 user_id = 1; string user_name = 2; string first_name = 3; } message UserRegisterRequest { string user_name = 1; string first_name = 2; string password = 3; } message UserRegisterResponse { string message = 1; } message UserLoginRequest { string user_name = 1; string password = 2; } message UserLoginResponse { bool success = 1; }
编译该文件:
$ protoc -I ./ --go_out=./ --micro_out=./ user.proto
目录结构:
├── domain │ ├── model │ │ └── user.go │ ├── repository │ │ └── user_repository.go │ └── service │ └── user_data_service.go ├── go.mod ├── go.sum ├── handler │ └── user.go ├── main.go ├── micro.mu └── proto └── user ├── user.pb.go ├── user.pb.micro.go └── user.proto
核心逻辑
domain/model/user.go
定义用户结构:
package model type User struct { ID int64 `gorm:"primary_key;not_null;auto_increment"` UserName string `gorm:"unique_index;not_null"` FirstName string HashPassword string }
domain/repository/user_repository.go
这部分代码包括创建数据库,初始化数据库表,增删改查用户信息
package repository import ( _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" "user/domain/model" ) type IUserRepository interface { InitTable() error // 初始化数据库表 FindUserByName(string) (*model.User, error) FindUserByID(int64) (*model.User, error) CreateUser(*model.User) (int64, error) DeleteUserByID(int64) error UpdateUser(*model.User) error FindAll() ([]model.User, error) } func NewUserRepository(db *gorm.DB) IUserRepository { return &UserRepository{db: db} } type UserRepository struct { db *gorm.DB } func (u *UserRepository) FindAll() ([]model.User, error) { userAll := make([]model.User, 0) return userAll, u.db.Find(&userAll).Error } // InitTable 初始化表 func (u *UserRepository) InitTable() error { if u.db.HasTable("users") { return nil } return u.db.CreateTable(&model.User{}).Error } func (u *UserRepository) FindUserByName(name string) (*model.User, error) { user := &model.User{} return user, u.db.Where("username = ?", name).Find(user).Error } func (u *UserRepository) FindUserByID(userID int64) (*model.User, error) { user := &model.User{} return user, u.db.First(user, userID).Error } func (u *UserRepository) CreateUser(user *model.User) (int64, error) { return user.ID, u.db.Create(user).Error } func (u *UserRepository) DeleteUserByID(userID int64) error { return u.db.Where("id = ?", userID).Delete(&model.User{}).Error } func (u *UserRepository) UpdateUser(user *model.User) error { return u.db.Model(user).Update(&user).Error }
domain/service/user_data_service.go
这部分代码包含业务逻辑,对用户数据进行操作
package service import ( "github.com/pkg/errors" "golang.org/x/crypto/bcrypt" "user/domain/model" "user/domain/repository" ) type IUserDataService interface { AddUser(*model.User) (int64, error) DeleteUser(int64) error UpdateUser(*model.User, bool) error FindUserByName(string) (*model.User, error) CheckPwd(string, string) (bool, error) } func NewUserDataService(userRepository repository.IUserRepository) IUserDataService { return &UserDataService{UserRepository: userRepository} } func GeneratePassword(userPassword string) ([]byte, error) { return bcrypt.GenerateFromPassword([]byte(userPassword), bcrypt.DefaultCost) } func ValidatePassword(userPassword string, hashed string) (bool, error) { if err := bcrypt.CompareHashAndPassword([]byte(hashed), []byte(userPassword)); err != nil { return false, errors.New("wrong password") } return true, nil } type UserDataService struct { UserRepository repository.IUserRepository } func (u *UserDataService) AddUser(user *model.User) (int64, error) { pwdByte, err := GeneratePassword(user.HashPassword) if err != nil { return user.ID, err } user.HashPassword = string(pwdByte) return u.UserRepository.CreateUser(user) } func (u *UserDataService) DeleteUser(userID int64) error { return u.UserRepository.DeleteUserByID(userID) } func (u *UserDataService) UpdateUser(user *model.User, isChangedPwd bool) error { if isChangedPwd { pwdByte, err := GeneratePassword(user.HashPassword) if err != nil { return err } user.HashPassword = string(pwdByte) } return u.UserRepository.UpdateUser(user) } func (u *UserDataService) FindUserByName(userName string) (*model.User, error) { return u.UserRepository.FindUserByName(userName) } func (u *UserDataService) CheckPwd(userName string, pwd string) (bool, error) { user, err := u.UserRepository.FindUserByName(userName) if err != nil { return false, err } return ValidatePassword(pwd, user.HashPassword) }
程序入口:
package main import ( "github.com/jinzhu/gorm" "go-micro.dev/v4" "log" "user/domain/repository" srv "user/domain/service" "user/handler" proto "user/proto/user" ) func main() { service := micro.NewService( micro.Name("go.micro.service.user"), micro.Version("latest")) service.Init() db, err := gorm.Open("mysql", "micro:123456@/micro?charset=utf8") if err != nil { log.Fatalln(err) } defer db.Close() resp := repository.NewUserRepository(db) resp.InitTable() db.SingularTable(true) userDataService := srv.NewUserDataService(repository.NewUserRepository(db)) err = proto.RegisterUserHandler(service.Server(), &handler.User{UserDataService: userDataService}) if err != nil { log.Fatalln(err) } if err = service.Run(); err != nil { log.Fatalln(err) } }
镜像打包
编写dockerfile打包应用
DockerFile常用命令:
-
FROM: 定制镜像基于FROM的镜像,后续操作都基于该镜像
-
RUN: 用于执行后面跟着的命令行命令
-
COPY,ADD: 复制指令,从文件或者目录到容器里制定路径
-
CMD,ENTRYPOINT: 用于运行程序
-
ENV: 设置环境变量,在后续指令中,就可以使用这个环境变量
-
EXPOSE: 声明端口
-
WORKDIR: 指定工作目录
-
USER: 于指定执行后续命令的用户和用户组
将源程序进行交叉编译为linux平台上的可执行程序:
$ CGO_ENABLE=0 GOOS=linux GOARCH=amd64 go build -o user *.go
编写Dockerfile:
FROM alpine ADD user /user ENTRYPOINT ["/user"]
使用以下命令配合Dockerfile即可进行打包:
$ sudo docker build -t user:latest .
使用该命令即可运行:
$ sudo docker run --rm -d user
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律