предисловие
Я записался в автошколу, но статьи не выкладывал более двух месяцев.На прошлой неделе наконец закончился экзамен по вождению.После этого я должен наверстать статьи за предыдущие два месяца. Я поставил перед собой цель, после прочтения исходников go-фреймворков, таких как beego, iris и gin, я уже разместил статью, которая тоже beego.golang framework анализ-beego, сегодня анализ Go Framework радужной оболочки, в основном, чтобы объяснить процесс жизненного цикла радужной оболочки.
Перед прочтением этой статьи, если вы не читалиgolang framework анализ-beegoВы можете сначала посмотреть, потому чтоgolang framework анализ-beegoговорить оКак запустить http сервер в go, Этот пункт знаний очень полезен для понимания этой статьи.
Установить
Установить со скольжением:
glide get github.com/kataras/iris
glide get github.com/kataras/golog
Запустите простой http-сервис iris:
//main.go
package main
import "github.com/kataras/iris"
func main() {
app := iris.Default()
app.Get("/ping", func(ctx iris.Context) {
ctx.JSON(iris.Map{
"message": "pong",
})
})
app.Run(iris.Addr(":8888"))
}
жизненный цикл ириса
Посетите адрес источника изображения, чтобы просмотреть увеличенное изображение cdn.tigerb.cn/20190628234814.png
На картинке выше показана блок-схема жизненного цикла фреймворка iris, которую я разобрал, когда читал код iris, с большим количеством контента. В целом он делится на четыре основные части:
оранжевая часть
Инициализировать iris.Application:
- Создать iris.Application
- Маршруты для создания APIBuilder (здесь регистрируются app.Get() и другие методы)
- Создайте маршрутизатор (каждый http-запрос обрабатывается маршрутизатором)
синяя часть
Регистрация маршрутов в app.APIBuilder
фиолетовая часть
Инициализировать http.Server
зеленая часть
Создайте обработчик маршрута и запустите http-сервер:
- регистр
app.APIBuilder
прибытьapp.Router.routesProvider
- регистр
app.APIBuilder.routes
направляется вapp.Router.requestHandler
- запустить http-сервер
Анализ кода ключей
- Создание приложения радужной оболочки
// Application 首先看看我们的iris Application结构体组成
type Application struct {
// 我们的路由都注册到了 APIBuilder
*router.APIBuilder
// *router.Router 实现了ServeHTTP方法 并且最终赋值给了&http.server{}.Handler
*router.Router
// 请求上下文池子
ContextPool *context.Pool
// 配置项
config *Configuration
// 日志
logger *golog.Logger
// 视图
view view.View
// 执行一次的once
once sync.Once
// 互斥锁
mu sync.Mutex
Hosts []*host.Supervisor
hostConfigurators []host.Configurator
}
// 创建了一个iris应用实例
// 为什么不直接New呢?
// 因为Default里面注册了两个handle
// 1. recover panic的方法,
// 2. 请求日志
app := iris.Default()
func Default() *Application {
app := New()
// 合成复用*APIBuilder的Use
app.Use(recover.New())
// 合成复用*APIBuilder的Use
app.Use(requestLogger.New())
return app
}
// app := New() 得到的结构体
app := &Application{
config: &config,
logger: golog.Default,
// 很关键:我们的路由都注册到了 APIBuilder
APIBuilder: router.NewAPIBuilder(),
// 很关键:*router.Router 实现了ServeHTTP方法 并且最终赋值给了&http.server{}.Handler
Router: router.NewRouter(),
}
// 注册api请求的中间件
func (api *APIBuilder) Use(handlers ...context.Handler) {
api.middleware = append(api.middleware, handlers...)
}
- о
router.NewAPIBuilder()
Свойство маршрутов APIBuilder очень важно, и определяемые нами окончательные маршруты регистрируются здесь.
// APIBuilder
api := &APIBuilder{
macros: macro.Defaults,
errorCodeHandlers: defaultErrorCodeHandlers(),
reporter: errors.NewReporter(),
relativePath: "/",
// 最终的我们定义的路由都是注册到了这里
routes: new(repository),
}
// repository的结构
type repository struct {
routes []*Route
}
Вывод: Маршрут пользователя зарегистрирован наapp.APIBuilder.routes
- о
router.NewRouter()
router.NewRouter()
возвращает&Router{}
указатель,&Router{}
Есть три ключевых свойства иServeHTTP
метод члена.
Три ключевых свойства:
mainHandler http.HandlerFunc
requestHandler RequestHandler
routesProvider RoutesProvider
Давайте снова посмотрим на методы-членыServeHTTP
ДостигнутоServeHTTP(w http.ResponseWriter, r *http.Request)
метод, то есть этот метод будет выполняться после принятия запроса, давайте посмотрим на содержание конкретного метода.
// implement ServeHTTP
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 所以这里可以看出accept请求之后会执行mainHandler
router.mainHandler(w, r)
}
func NewRouter() *Router { return &Router{} }
type Router struct {
mu sync.Mutex
requestHandler RequestHandler
// 每次http请求都会执行mainHandler
mainHandler http.HandlerFunc
wrapperFunc func(http.ResponseWriter, *http.Request, http.HandlerFunc)
cPool *context.Pool r
routesProvider RoutesProvider
}
// implement ServeHTTP
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 每次http请求都会执行mainHandler
router.mainHandler(w, r)
}
Вывод: каждый http запрос будет выполненmainHandler
- зарегистрировать маршрут
Здесь очень просто, что зарегистрированный пользователь перенаправляется наapp.APIBuilder.routes
//router
func (api *APIBuilder) Get(relativePath string, handlers ...context.Handler) *Route {
return api.Handle(http.MethodGet, relativePath, handlers...)
}
route := &Route{
Name: defaultName,
Method: method,
methodBckp: method,
Subdomain: subdomain,
tmpl: tmpl,
Path: path,
Handlers: handlers,
MainHandlerName: mainHandlerName,
FormattedPath: formattedPath,
}
- построить обработчик запроса
//启动路由
app.Run()
⬇️
// 构建
app.Build()
⬇️
// 构建路由
app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false)
⬇️
// 构建请求Handler
// 把app.APIBuilder注册的api注册到了requestHandler里
// 因为我们在下面发现请求都是从router.requestHandler去处理的
requestHandler.Build(routesProvider)
⬇️
// 赋值
router.requestHandler = requestHandler
router.routesProvider = routesProvider
⬇️
// the important 没错很重要的地方mainHandler被赋值的地方
// 也就是accpet请求实际执行的代码
// 真相就在这
// the important
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
// 构建请求上下文
ctx := cPool.Acquire(w, r)
// 处理请求
router.requestHandler.HandleRequest(ctx)
// 释放请求上下文
cPool.Release(ctx)
}
⬇️
// 实际处理请求饿地方
// 路由的匹配就是这里了
func (h *routerHandler) HandleRequest(ctx context.Context)
- Запустить HTTP-сервер
Наконец, мы запускаем http-сервер, который в основном такой же, как и у большинства http-сервисов golang.
// 赋值http服务的ip+port
iris.Addr(":8888")
⬇️
//创建http.Server并启动服务的匿名方法
func Addr(addr string, hostConfigs ...host.Configurator) Runner {
return func(app *Application) error {
return app.NewHost(&http.Server{Addr: addr}).
Configure(hostConfigs...).
ListenAndServe()
}
}
⬇️
// app.NewHost(&http.Server{Addr: addr})
// 就是这里赋值app.Router给http.Server的Handler的
if srv.Handler == nil {
srv.Handler = app.Router
}
⬇️
// 启动服务
su.Server.Serve(l)
⬇️
// accept请求
l.Accept()
⬇️
// 启动一个goroutine处理请求
go c.serve(ctx)
⬇️
// 最终至此真相都大白了
serverHandler{c.server}.ServeHTTP(w, w.req)
Эпилог
Наконец, мы кратко рассмотрим описанный выше процесс:
Ссылки на серию статей "golang framework analysis" следующие: