Golang中使用gRPC时如何组织代码结构
Golang中使用gRPC时如何组织代码结构 大家好。我刚开始接触GO并用它编写微服务。我练习了几个专门编写后端的项目。我想为自己写一个新闻门户网站。我已经为数据库解析了几个新闻网站。并且我为我的门户网站编写了一个REST管理面板。现在我想在gRPC上编写门户网站本身的后端。问题是如何正确组织代码结构。用gRPC编写的项目示例也会非常有帮助。也欢迎任何处理过gRPC的人提供建议。
2 回复
这种结构示例很常见,https://github.com/GoogleCloudPlatform/microservices-demo
我使用 pb 包来存储 proto 文件,每个微服务都有一个 shell 脚本来获取这个 proto 文件,并将其包含在我的应用程序中,然后生成缓冲区消息,请看链接中的示例
src/
cartservice/
pb/
cart.pb.go (由 genproto.sh 生成)
genproto.sh
sessionservice/
pb/
session.proto.go (由 genproto.sh 生成)
genproto.sh
....
pb/
cart.proto
session.proto
更多关于Golang中使用gRPC时如何组织代码结构的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中使用gRPC时,合理的代码结构对于维护和扩展至关重要。以下是一个典型的项目结构示例:
project/
├── cmd/
│ └── server/
│ └── main.go
├── internal/
│ ├── handler/
│ │ └── news_handler.go
│ ├── service/
│ │ └── news_service.go
│ └── repository/
│ └── news_repository.go
├── pkg/
│ ├── pb/
│ │ ├── news.pb.go
│ │ └── news_grpc.pb.go
│ └── config/
│ └── config.go
├── proto/
│ └── news.proto
└── go.mod
首先定义proto文件:
// proto/news.proto
syntax = "proto3";
package news;
option go_package = "github.com/yourname/project/pkg/pb";
service NewsService {
rpc GetArticle(GetArticleRequest) returns (Article);
rpc ListArticles(ListArticlesRequest) returns (ListArticlesResponse);
}
message GetArticleRequest {
string id = 1;
}
message Article {
string id = 1;
string title = 2;
string content = 3;
string created_at = 4;
}
message ListArticlesRequest {
int32 page = 1;
int32 page_size = 2;
}
message ListArticlesResponse {
repeated Article articles = 1;
int32 total = 2;
}
生成gRPC代码:
protoc --go_out=. --go-grpc_out=. proto/news.proto
实现服务层:
// internal/service/news_service.go
package service
import (
"context"
"github.com/yourname/project/internal/repository"
"github.com/yourname/project/pkg/pb"
)
type NewsService struct {
repo repository.NewsRepository
pb.UnimplementedNewsServiceServer
}
func NewNewsService(repo repository.NewsRepository) *NewsService {
return &NewsService{repo: repo}
}
func (s *NewsService) GetArticle(ctx context.Context, req *pb.GetArticleRequest) (*pb.Article, error) {
article, err := s.repo.GetByID(ctx, req.Id)
if err != nil {
return nil, err
}
return &pb.Article{
Id: article.ID,
Title: article.Title,
Content: article.Content,
CreatedAt: article.CreatedAt.Format(time.RFC3339),
}, nil
}
func (s *NewsService) ListArticles(ctx context.Context, req *pb.ListArticlesRequest) (*pb.ListArticlesResponse, error) {
articles, total, err := s.repo.List(ctx, int(req.Page), int(req.PageSize))
if err != nil {
return nil, err
}
pbArticles := make([]*pb.Article, len(articles))
for i, article := range articles {
pbArticles[i] = &pb.Article{
Id: article.ID,
Title: article.Title,
Content: article.Content,
CreatedAt: article.CreatedAt.Format(time.RFC3339),
}
}
return &pb.ListArticlesResponse{
Articles: pbArticles,
Total: int32(total),
}, nil
}
实现处理器:
// internal/handler/news_handler.go
package handler
import (
"net"
"github.com/yourname/project/internal/service"
"github.com/yourname/project/pkg/pb"
"google.golang.org/grpc"
)
type GRPCServer struct {
server *grpc.Server
}
func NewGRPCServer(newsService *service.NewsService) *GRPCServer {
grpcServer := grpc.NewServer()
pb.RegisterNewsServiceServer(grpcServer, newsService)
return &GRPCServer{
server: grpcServer,
}
}
func (s *GRPCServer) Serve(addr string) error {
lis, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return s.server.Serve(lis)
}
func (s *GRPCServer) GracefulStop() {
s.server.GracefulStop()
}
主程序入口:
// cmd/server/main.go
package main
import (
"log"
"github.com/yourname/project/internal/handler"
"github.com/yourname/project/internal/repository"
"github.com/yourname/project/internal/service"
)
func main() {
// 初始化依赖
repo := repository.NewNewsRepository()
newsService := service.NewNewsService(repo)
grpcServer := handler.NewGRPCServer(newsService)
// 启动gRPC服务器
log.Println("Starting gRPC server on :50051")
if err := grpcServer.Serve(":50051"); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}
这种分层结构将业务逻辑(service)、数据访问(repository)和传输层(handler)分离,使代码更易于测试和维护。gRPC服务实现直接嵌入生成的UnimplementedNewsServiceServer,确保向前兼容。

