|
一:首先man.go,整个程序的入口
func main() {
beego.Run()
}
然后beego.run()代码
// Run beego application.
// beego.Run() default run on HttpPort
// beego.Run(":8089")
// beego.Run("127.0.0.1:8089")
func Run(params ...string) {
if len(params) > 0 && params[0] != "" {
strs := strings.Split(params[0], ":")
if len(strs) > 0 && strs[0] != "" {
HttpAddr = strs[0]
}
if len(strs) > 1 && strs[1] != "" {
HttpPort, _ = strconv.Atoi(strs[1])
}
}
initBeforeHttpRun()
if EnableAdmin {
go beeAdminApp.Run()
}
BeeApp.Run()
}
可以看出来,beego.run()可以带参数。
beego.run()在默认的主机、端口号上运行,beego.run(port)在给定的端口号、默认的主机上运行。beego.run(addr:post)在给定的主机和端口上运行。
下面看看initBeforeHttpRun()的代码。
func initBeforeHttpRun() {
// if AppConfigPath not In the conf/app.conf reParse config
if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") {
err := ParseConfig()
if err != nil && AppConfigPath != filepath.Join(workPath, "conf", "app.conf") {
// configuration is critical to app, panic here if parse failed
panic(err)
}
}
// do hooks function
for _, hk := range hooks {
err := hk()
if err != nil {
panic(err)
}
}
if SessionOn {
var err error
sessionConfig := AppConfig.String("sessionConfig")
if sessionConfig == "" {
sessionConfig = `{"cookieName":"` + SessionName + `",` +
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
`"providerConfig":"` + SessionSavePath + `",` +
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
`"sessionIDHashFunc":"` + SessionHashFunc + `",` +
`"sessionIDHashKey":"` + SessionHashKey + `",` +
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
`"domain":"` + SessionDomain + `",` +
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
}
GlobalSessions, err = session.NewManager(SessionProvider,
sessionConfig)
if err != nil {
panic(err)
}
go GlobalSessions.GC()
}
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
Warn(err)
}
}
middleware.VERSION = VERSION
middleware.AppName = AppName
middleware.RegisterErrorHandler()
if EnableDocs {
Get("/docs", serverDocs)
Get("/docs/*", serverDocs)
}
//init mime
AddAPPStartHook(initMime)
}
可以看到首先拼凑出来的是conf配置文件的路劲,如果存在然后调用ParseConfig()解析conf。
然后是
for _, hk := range hooks {
err := hk()
if err != nil {
panic(err)
}
}
hooks的定义
type hookfunc func() error //hook function to run
var hooks []hookfunc //hook function slice to store the hookfunc
func init() {
hooks = make([]hookfunc, 0)
}
hooks是一个hookfun的切片,
// The hookfunc will run in beego.Run()
// such as sessionInit, middlerware start, buildtemplate, admin start
func AddAPPStartHook(hf hookfunc) {
hooks = append(hooks, hf)
}
上面的代码是在启动的时候添加自己的方法hook。也就是hooks是在启动之前,留给用户初始化一些东西的时候。
if SessionOn {
var err error
sessionConfig := AppConfig.String("sessionConfig")
if sessionConfig == "" {
sessionConfig = `{"cookieName":"` + SessionName + `",` +
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
`"providerConfig":"` + SessionSavePath + `",` +
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
`"sessionIDHashFunc":"` + SessionHashFunc + `",` +
`"sessionIDHashKey":"` + SessionHashKey + `",` +
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
`"domain":"` + SessionDomain + `",` +
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
}
GlobalSessions, err = session.NewManager(SessionProvider,
sessionConfig)
if err != nil {
panic(err)
}
go GlobalSessions.GC()
}
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
Warn(err)
}
}
下面就开始来解析conf文件。如果sessionConfig为空,就使用默认的json数据。然后就开始根据提供的config配置文件创建一个sessionmanager对象
这是session.NewManager()方法的实现
// Create new Manager with provider name and json config string.
// provider name:
// 1. cookie
// 2. file
// 3. memory
// 4. redis
// 5. mysql
// json config:
// 1. is https default false
// 2. hashfunc default sha1
// 3. hashkey default beegosessionkey
// 4. maxage default is none
func NewManager(provideName, config string) (*Manager, error) {
provider, ok := provides[provideName]
if !ok {
return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName)
}
cf := new(managerConfig)
cf.EnableSetCookie = true
err := json.Unmarshal([]byte(config), cf)
if err != nil {
return nil, err
}
if cf.Maxlifetime == 0 {
cf.Maxlifetime = cf.Gclifetime
}
err = provider.SessionInit(cf.Maxlifetime, cf.ProviderConfig)
if err != nil {
return nil, err
}
if cf.SessionIDHashFunc == "" {
cf.SessionIDHashFunc = "sha1"
}
if cf.SessionIDHashKey == "" {
cf.SessionIDHashKey = string(generateRandomKey(16))
}
return &Manager{
provider,
cf,
}, nil
}
可以推测。session.NewManager(SessionProvider,sessionConfig)中SessionProvider是一个全局变量,使用的是在config.go中默认的SessionProvider = "memory",然后改方法返回的是一个Manager的指针对象,即*Manager,所以GlobalSessions是一个*Manager对象。
然后启动一个携程执行GC()方法。下面是GC的源码
// Start session gc process.
// it can do gc in times after gc lifetime.
func (manager *Manager) GC() {
manager.provider.SessionGC()
time.AfterFunc(time.Duration(manager.config.Gclifetime)*time.Second, func() { manager.GC() })
}
所以上面的代码是一个无限循环,每隔一段time。DUration之后执行GC().
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
Warn(err)
}
}
这里就开始编译模板了。
// build all template files in a directory.
// it makes beego can render any template file in view directory.
func BuildTemplate(dir string) error {
if _, err := os.Stat(dir); err != nil {
if os.IsNotExist(err) {
return nil
} else {
return errors.New("dir open err")
}
}
self := &templatefile{
root: dir,
files: make(map[string][]string),
}
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
return self.visit(path, f, err)
})
if err != nil {
fmt.Printf("filepath.Walk() returned %v\n", err)
return err
}
for _, v := range self.files {
for _, file := range v {
t, err := getTemplate(self.root, file, v...)
if err != nil {
Trace("parse template err:", file, err)
} else {
BeeTemplates[file] = t
}
}
}
return nil
}
首先判断目录是否存在。目录ViewsPath在config中有初始化。然后初始化templatefile结构体,filepath.Walk()走一边目录里的文件,记录在self.files里面。循环self.files中的file(map[dir][]file]),用getTemplate获取template.Template实例,保存在beego.BeeTemplates(map[string]template.Template)。
然后是
middleware.VERSION = VERSION
middleware.AppName = AppName
middleware.RegisterErrorHandler()
if EnableDocs {
Get("/docs", serverDocs)
Get("/docs/*", serverDocs)
}
//init mime
AddAPPStartHook(initMime)
middleware包括的是错误处理的功能。如NotFound()、Forbidden()、Errorhandler()等等处理。。
随后的AddAPPStartHook(initMine)则是初始化所有的minetype类型的函数。
上面的代码实在beego项目启动前需要操作的比如初始化conf配置、编译模板文件、注册错误处理中间件、加载所有的mimetype类型、
然后继续回到beego.run()代码中间
if EnableAdmin {
go beeAdminApp.Run()
}
BeeApp.Run()
很简单。如果beego允许admin。则执行beeAdminApp。beeAdminApp也是一个*beego.adminApp,负责系统监控、性能检测、访问统计和健康检查等。然后猪线程运行BeeApp.Run()方法,开始执行beego。
下面看看beego.adminApp的代码
// adminApp is an http.HandlerFunc map used as beeAdminApp.
type adminApp struct {
routers map[string]http.HandlerFunc
}
// Route adds http.HandlerFunc to adminApp with url pattern.
func (admin *adminApp) Route(pattern string, f http.HandlerFunc) {
admin.routers[pattern] = f
}
// Run adminApp http server.
// Its addr is defined in configuration file as adminhttpaddr and adminhttpport.
func (admin *adminApp) Run() {
if len(toolbox.AdminTaskList) > 0 {
toolbox.StartTask()
}
addr := AdminHttpAddr
if AdminHttpPort != 0 {
addr = fmt.Sprintf("%s:%d", AdminHttpAddr, AdminHttpPort)
}
for p, f := range admin.routers {
http.Handle(p, f)
}
err := http.ListenAndServe(addr, nil)
if err != nil {
BeeLogger.Critical("Admin ListenAndServe: ", err)
}
}
// task interface
type Tasker interface {
GetStatus() string
Run() error
SetNext(time.Time)
GetNext() time.Time
SetPrev(time.Time)
GetPrev() time.Time
}
AdminTaskList map[string]Tasker
// start all tasks
func StartTask() {
isstart = true
go run()
}
func run() {
now := time.Now().Local()
for _, t := range AdminTaskList {
t.SetNext(now)
}
for {
sortList := NewMapSorter(AdminTaskList)
sortList.Sort()
var effective time.Time
if len(AdminTaskList) == 0 || sortList.Vals[0].GetNext().IsZero() {
// If there are no entries yet, just sleep - it still handles new entries
// and stop requests.
effective = now.AddDate(10, 0, 0)
} else {
effective = sortList.Vals[0].GetNext()
}
select {
case now = |
|