preface
Reported a driving school, when more than two months did not send an article, driving test last week finally ended, after this have to make up for the first two months of the article. Before, I set a goal to read the source code of Beego, Iris, gin and other GO frameworks. Before, I have published an article that is too beeGO – Golang framework analysis – Beego. Today, I bring the analysis of IRIS of GO framework, mainly explaining a life cycle process of IRIS framework.
If you haven’t read golang beego before reading this article, you should check it out. Golang Beego explains how to start an HTTP server.
The installation
Install using Glide:
glide get github.com/kataras/iris
glide get github.com/kataras/golog
Copy the code
Start a simple IRIS HTTP service:
//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"))}Copy the code
Life cycle of IRIS
Access to a larger picture source address to check the CDN. Tigerb. Cn / 20190628234814 PNG
The figure above is a life cycle flow chart of IRIS framework that I sorted out when I read the IRIS code. Generally divided into four major parts:
The orange part
Initialize the iris. Application:
- Create iris. Application
- Create APIBuilder(routes for methods like app.get () are registered here)
- Create a Router(through which each HTTP request is processed)
The blue part
Register routing to app.APIBuilder
The purple part
Initialize an HTTP. Server
The green part
Build route handler& start HTTP server:
- registered
app.APIBuilder
toapp.Router.routesProvider
- registered
app.APIBuilder.routes
The route toapp.Router.requestHandler
- Start the HTTP server
Key code parsing
- Create an Iris Application
// Application first look at our Iris Application structure composition
type Application struct {
// Our routes are registered with the APIBuilder
*router.APIBuilder
// *router.Router implements the ServeHTTP method and is ultimately assigned to &http.server{}.handler
*router.Router
// Request context pool
ContextPool *context.Pool
/ / configuration items
config *Configuration
/ / log
logger *golog.Logger
/ / view
view view.View
// Perform once
once sync.Once
/ / the mutex
mu sync.Mutex
Hosts []*host.Supervisor
hostConfigurators []host.Configurator
}
// Create an iris application instance
// Why not just New?
// Because there are two Handles registered in Default
// 1. Recover panic.
// 2. Request log
app := iris.Default()
func Default(a) *Application {
app := New()
// The Use of the APIBuilder
app.Use(recover.New())
// The Use of the APIBuilder
app.Use(requestLogger.New())
return app
}
// app := New(
app := &Application{
config: &config,
logger: golog.Default,
// Critical: our routes are registered with the APIBuilder
APIBuilder: router.NewAPIBuilder(),
Router implements the ServeHTTP method and is ultimately assigned to &http.server{}.handler
Router: router.NewRouter(),
}
// Register the middleware requested by the API
func (api *APIBuilder) Use(handlers ... context.Handler) {
api.middleware = append(api.middleware, handlers...)
}
Copy the code
- about
router.NewAPIBuilder()
The routes attribute of the APIBuilder is key, and finally all the routes we define are registered here.
// APIBuilder
api := &APIBuilder{
macros: macro.Defaults,
errorCodeHandlers: defaultErrorCodeHandlers(),
reporter: errors.NewReporter(),
relativePath: "/".// The final routes we define are registered here
routes: new(repository),
}
// The repository structure
type repository struct {
routes []*Route
}
Copy the code
Conclusion: The user is registered with app.apiBuilder.routes
- about
router.NewRouter()
Router.newrouter () returns a pointer to &Router{} with three key attributes and a ServeHTTP member method.
Three key attributes:
mainHandler http.HandlerFunc
requestHandler RequestHandler
routesProvider RoutesProvider
ServeHTTP implements ServeHTTP(w http.responseWriter, r * http.request), which accepts the Request and executes it.
// implement ServeHTTP func (router *Router) ServeHTTP(w http.ResponseWriter, R * http.request) {mainHandler router.mainHandler(w, r)}Copy the code
func NewRouter(a) *Router { return &Router{} }
type Router struct {
mu sync.Mutex
requestHandler RequestHandler
// Each HTTP request executes 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) {
// Each HTTP request executes mainHandler
router.mainHandler(w, r)
}
Copy the code
Conclusion: mainHandler is executed for every HTTP request
- Registered routing
Apibuilder.routes To 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,
}
Copy the code
- Build request Handler
// Start the routeApp. The Run () ⬇ ️/ / buildApp. The Build () ⬇ ️// Build the route
app.Router.BuildRouter(app.ContextPool, routerHandler, app.APIBuilder, false) ⬇ ️// Build request Handler
// Register the API registered with app.APIBuilder into requestHandler
// Because we found below that requests are processed from router. RequestHandlerRequestHandler. Build (routesProvider) ⬇ ️/ / assignmentRouter. requestHandler = requestHandler router.routesProvider = routesProvider ⬇️// The important place where mainHandler is assigned
// This is the code that accPET requests actually execute
// The truth is out there
// the important
router.mainHandler = func(w http.ResponseWriter, r *http.Request) {
// Build the request context
ctx := cPool.Acquire(w, r)
// Process the request
router.requestHandler.HandleRequest(ctx)
// Release the request contextCPool. Release (CTX)} ⬇ ️// Actually process the request hungry place
// The route matches here
func (h *routerHandler) HandleRequest(ctx context.Context)
Copy the code
- Start the HTTP Server
Finally, we start the HTTP server, which is basically the same as most Golang HTTP service starts.
// Assign the IP +port of the HTTP service
iris.Addr(": 8888") ⬇ ️// Create http.Server and start the anonymous method of the service
func Addr(addr string, hostConfigs ... host.Configurator) Runner {
return func(app *Application) error {
returnapp.NewHost(&http.Server{Addr: addr}). Configure(hostConfigs...) .listenandServe ()}} ⬇️// app.NewHost(&http.Server{Addr: addr})
// This is where app.Router is assigned to the http.Server Handler
if srv.Handler == nil{srv.handler = app.router} ⬇️// Start the serviceSu. Server. Serve (l) ⬇ ️/ / the accept requestL.A. ccept () ⬇ ️// Start a goroutine to process the request
goC.s. erve (CTX) ⬇ ️// At last the truth came out
serverHandler{c.server}.ServeHTTP(w, w.req)
Copy the code
conclusion
Finally, let’s briefly review the above process:
The Golang Framework Analysis series is linked below:
- Golang Framework Analysis – Beego
- Golang Framework analysis – Iris