preface

Maybe beego framework should be the first choice for many PHPer to switch to GO in China, because BEEgo MVC, ORM and perfect Chinese documents make PHPer feel comfortable, and there is no doubt that I am also. This feels like starting PHP with ThinkPHP.

Maybe with the improvement of your cognition, you will hate the present things, for example, one day you may gradually start to hate BeeGo, you will find the real meaning of the package in go language, you will start to reflect on MVC is really suitable for GO, or you will start to feel ORM in static language chicken side, etc. I just want to say: “Maybe you have grown ~”. But that doesn’t matter. Every popular thing has its lessons to learn. Today’s article is very simple, just like a note, which records my reading of Beego source code in these days.

How to read a frame?

No doubt the framework for reading Go is the same as the PHP framework:

  1. Configuration loading: How to load configuration files.
  2. Routing: Analyzes how the framework performs corresponding services through URIs.
  3. ORM: How ORM is implemented.

Here (1.) and (3.) are just loading a file and an implementation of the SQL parser, which I will ignore and focus on the implementation of the routing.

The installation

Briefly:

// Step1: Install beego go get github.com/astaxie/beego // Step2: Install Bee go get github.com/beego/bee // Step3: Create a new project with the Bee tool bee New Beego-code-readCopy the code

The code analysis

Go has its own implementation of the HTTP package, and most GO frameworks are based on this HTTP package, so let’s supplement or review this knowledge before we look at BeeGo. As follows:

How does GO start an HTTP server

package main

import (
	// Import the net/http package
	"net/http"
)

func main(a) {
	/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- using HTTP start an HTTP service packages a -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
	// *http.Request Specifies a pointer to the HTTP Request content instance
	// http.ResponseWriter Writes an instance of the HTTP response
	http.HandleFunc("/v1/demo".func(w http.ResponseWriter, r *http.Request) {
		// Write the response
		w.Write([]byte("Hello TIGERB ! \n"))})// Start an HTTP service and listen on port 8888 where the second argument can specify handler
	http.ListenAndServe(": 8888".nil)}// Test our service
// --------------------
// Start: bee run
/ / access: curl "http://127.0.0.1:8888/v1/demo"
// Response result: Hello TIGERB!
Copy the code

ListenAndServe is a further encapsulation of HTTP.Server. In addition to the above methods, you can also directly start the service using HTTP. This Handler’s ServeHTTP method is executed when the request comes in, as follows:

package main

// Import the net/http package
import (
	"net/http"
)

// DemoHandle Server Handle example
type DemoHandle struct{}// ServeHTTP method executed after the route is matched
func (DemoHandle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello TIGERB ! \n"))}func main(a) {
	/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- using the HTTP Server start an HTTP service packages 2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
	// Initialize an http.server
	server := &http.Server{}
	// Initialize handler and assign it to server.handler
	server.Handler = DemoHandle{}
	// Bind the address
	server.Addr = ": 8888"

	// Start an HTTP service
	server.ListenAndServe()

}

// Test our service
// --------------------
// Start: bee run
/ / access: curl "http://127.0.0.1:8888/v1/demo"
// Response result: Hello TIGERB!
Copy the code

Beego Routing analysis

Next, let’s look at beego’s code. Taking access to “http://127.0.0.1:8080/” as an example, there are three key points for beego code, which are as follows:

  1. Start: main.go -> beego.run ()

  2. Registered routing: routers \ router go – > beego. The router (“/”, & controllers. MainController {})

  3. Controller: Controllers \default.go -> Get()

Here’s a breakdown of the three key points:

Beego.run () is the main job

// github.com/astaxie/beego/beego.go
func Run(params ...string) {
	// Some initialization before starting the HTTP service is ignored below
	initBeforeHTTPRun()

	// Ip&port Settings for the HTTP service
	if len(params) > 0 && params[0] != "" {
		strs := strings.Split(params[0].":")
		if len(strs) > 0 && strs[0] != "" {
			BConfig.Listen.HTTPAddr = strs[0]}if len(strs) > 1 && strs[1] != "" {
			BConfig.Listen.HTTPPort, _ = strconv.Atoi(strs[1])}}// Another run looks down
	BeeApp.Run()
}
Copy the code
// github.com/astaxie/beego/app.go
func (app *App) Run(mws ... MiddleWare) {
	/ /... omit

	// The type of app.Server is *http.Server, which is a native HTTP package and is the second way to start an HTTP Server
	app.Server.Handler = app.Handlers

	/ /... omit

	if BConfig.Listen.EnableHTTP {
		go func(a) {
			app.Server.Addr = addr
			logs.Info("http server Running on http://%s", app.Server.Addr)

			// The default value is false
			if BConfig.Listen.ListenTCP4 {
				/ /...
				// Ignore the default false
			} else {
				// Key points ListenAndServe: app.Server is of type *http.Server so the HTTP service is started
				iferr := app.Server.ListenAndServe(); err ! =nil {
					logs.Critical("ListenAndServe: ", err)
					time.Sleep(100 * time.Microsecond)
					endRunning <- true(1)}}}}// Block until the service starts
	<-endRunning
}

// See that HTTP has been started and is the way to register the Handler
Copy the code

And then we go to the ServeHTTP method of this Handler, and we go to app.server.Handler = app.Handlers, and we find the following definition, Handler is the ControllerRegister value, Kiss every time so please come will go perform ControllerRegister. ServeHTTP (rw HTTP ResponseWriter, r * HTTP. Request).

// src/github.com/astaxie/beego/app.go
func init(a) {
	// Call the method that creates an instance of the BeeGo framework
	BeeApp = NewApp()
}

// App structure
type App struct {
	// Critical request callback Handler
	Handlers *ControllerRegister
	// HTTP packet services
	Server   *http.Server
}

func NewApp(a) *App {
	// Initialize the HTTP handler
	cr := NewControllerRegister()
	// Create a Beego instance
	app := &App{Handlers: cr, Server: &http.Server{}}
	return app
}

Copy the code

So far, we’ve been following the beego.run () code:

  1. The service started using the HTTP package
  2. Don’t usehttp.HandleFun()Defines the routing policy, but registers the Handler’s way

So through the beego beego. The Router () his management of routing, a HTTP Request to a callback ControllerRegister. ServeHTTP (rw HTTP ResponseWriter, r * HTTP. Request) method, In ControllerRegister. ServeHTTP (rw HTTP ResponseWriter, R * HTTP. Request) method to match routes and implement the corresponding controller (beegoControllerInterface) method, such as RESTFUL or custom.

Beego.router () how to register a route

First of all, how to load the routing file? We found that the routing package was imported in the main.go file:

package main

import (
	// Only the init method is used to import the Routers package
	_ "beego-code-read/routers"

	"github.com/astaxie/beego"
)

func main(a) {
	beego.Run()
}
Copy the code

The key is how beego.router () registers the routes. The code is as follows:

beego.Router() 
-> BeeApp.Handlers.Add(rootpath, c, mappingMethods...) 
-> ControllerRegister.addWithMethodParams(pattern, c, nil, mappingMethods...) 
-> ControllerRegister.addToRouter(method, pattern string, r *ControllerInfo) 
-> *Tree.AddRouter(pattern string, runObject interface{})
Copy the code

* tree.addrouter (); * tree.addrouter ();

Note: Go import package is equivalent to the process of pushing package. Import package first and then execute init