Go Revel - main函数分析
运行revel命令时,首先会编译整个项目,在编译时,会根据`app.conf`配置文件生成两个源码文件`tmp/main.go`、`routes/routes.go`,其中`main.go`是整个项目的入口。
## main.go与routes.go源码生成过程

源码在revel的`revel/harness`包。
https://github.com/robfig/revel/blob/master/harness/build.go
`main.go`的生成比较重要,而`routes.go`源码则是完全根据`conf/routes`配置文件的规则生成。
----------
## main.go分析
这里以booking示例项目为例子。
**包的导入**
模板:
import (
"flag"
"reflect"
"github.com/robfig/revel"{{range $k, $v := $.ImportPaths}}
{{$v}} "{{$k}}"{{end}}
)
渲染后:
import (
"flag"
"reflect"
"github.com/robfig/revel"
_ "booking/app"
controllers "booking/app/controllers"
_ "booking/app/jobs"
tests "booking/tests"
_ "github.com/mattn/go-sqlite3"
controllers0 "github.com/robfig/revel/modules/jobs/app/controllers"
_ "github.com/robfig/revel/modules/jobs/app/jobs"
controllers2 "github.com/robfig/revel/modules/static/app/controllers"
_ "github.com/robfig/revel/modules/testrunner/app"
controllers1 "github.com/robfig/revel/modules/testrunner/app/controllers"
models "github.com/robfig/revel/samples/booking/app/models"
)
这里动态的渲染出需要导入的包,必要时使用别名,导入包由`calcImportAliases`方法生成。
**注册控制器**
`mian`中进行控制器(controller)的注册
模板:
{{range $i, $c := .Controllers}}
revel.RegisterController((*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil),
[]*revel.MethodType{
{{range .MethodSpecs}}&revel.MethodType{
Name: "{{.Name}}",
Args: []*revel.MethodArg{ {{range .Args}}
&revel.MethodArg{Name: "{{.Name}}", Type: reflect.TypeOf((*{{index $.ImportPaths .ImportPath | .TypeExpr.TypeName}})(nil)) },{{end}}
},
RenderArgNames: map[int][]string{ {{range .RenderCalls}}
{{.Line}}: []string{ {{range .Names}}
"{{.}}",{{end}}
},{{end}}
},
},
{{end}}
})
{{end}}
渲染后:
...
revel.RegisterController((*controllers.Hotels)(nil),
[]*revel.MethodType{
&revel.MethodType{
Name: "Index",
Args: []*revel.MethodArg{
},
RenderArgNames: map[int][]string{
37: []string{
"bookings",
},
},
},
&revel.MethodType{
Name: "List",
Args: []*revel.MethodArg{
&revel.MethodArg{Name: "search", Type: reflect.TypeOf((*string)(nil)) },
&revel.MethodArg{Name: "size", Type: reflect.TypeOf((*int)(nil)) },
&revel.MethodArg{Name: "page", Type: reflect.TypeOf((*int)(nil)) },
},
RenderArgNames: map[int][]string{
58: []string{
"hotels",
"search",
"size",
"page",
"nextPage",
},
},
},
&revel.MethodType{
Name: "Show",
Args: []*revel.MethodArg{
&revel.MethodArg{Name: "id", Type: reflect.TypeOf((*int)(nil)) },
},
RenderArgNames: map[int][]string{
89: []string{
"title",
"hotel",
},
},
},
&revel.MethodType{
Name: "Settings",
Args: []*revel.MethodArg{
},
RenderArgNames: map[int][]string{
93: []string{
},
},
},
&revel.MethodType{
Name: "SaveSettings",
Args: []*revel.MethodArg{
&revel.MethodArg{Name: "password", Type: reflect.TypeOf((*string)(nil)) },
&revel.MethodArg{Name: "verifyPassword", Type: reflect.TypeOf((*string)(nil)) },
},
RenderArgNames: map[int][]string{
},
},
&revel.MethodType{
Name: "ConfirmBooking",
Args: []*revel.MethodArg{
&revel.MethodArg{Name: "id", Type: reflect.TypeOf((*int)(nil)) },
&revel.MethodArg{Name: "booking", Type: reflect.TypeOf((*models.Booking)(nil)) },
},
RenderArgNames: map[int][]string{
144: []string{
"title",
"hotel",
"booking",
},
},
},
&revel.MethodType{
Name: "CancelBooking",
Args: []*revel.MethodArg{
&revel.MethodArg{Name: "id", Type: reflect.TypeOf((*int)(nil)) },
},
RenderArgNames: map[int][]string{
},
},
&revel.MethodType{
Name: "Book",
Args: []*revel.MethodArg{
&revel.MethodArg{Name: "id", Type: reflect.TypeOf((*int)(nil)) },
},
RenderArgNames: map[int][]string{
163: []string{
"title",
"hotel",
},
},
},
})
...
`RegisterController`接受两个参数,`(c interface{}, methods []*MethodType)`,代码中,第一个参数传入`(*controllers.Hotels)(nil)`,其实是一个`controllers.Hotels`类型的空指针,方法内部会根据这个类型指针获取这个controller的结构名;第二个参数为这个controller所有Action的集合 `[]*MethodType`。
每一个`MethodType`对应一个Action, Action即符合绑定于`controller`并且暴露出来而且返回值为`revel.Result`的方法,参数不限。
例如:
// Action
&revel.MethodType{
// Action的名称,即方法名
Name: "List",
// Action所接受的参数,即方法的参数
Args: []*revel.MethodArg{
// 每个参数的变量名称,以及反射类型
&revel.MethodArg{Name: "search", Type: reflect.TypeOf((*string)(nil)) },
&revel.MethodArg{Name: "size", Type: reflect.TypeOf((*int)(nil)) },
&revel.MethodArg{Name: "page", Type: reflect.TypeOf((*int)(nil)) },
},
// 返回Result时调用Render来渲染模板的参数名
RenderArgNames: map[int][]string{
// 这里获取了调用Render时源码中的行号,行号是在异常时显示出来方便调试定位(感觉是这样)
58: []string{
"hotels",
"search",
"size",
"page",
"nextPage",
},
},
},
**注册验器**
模板:
revel.DefaultValidationKeys = map[string]map[int]string{ {{range $path, $lines := .ValidationKeys}}
"{{$path}}": { {{range $line, $key := $lines}}
{{$line}}: "{{$key}}",{{end}}
},{{end}}
}
渲染后:
revel.DefaultValidationKeys = map[string]map[int]string{
"booking/app/controllers.Application.SaveUser": {
55: "verifyPassword",
56: "verifyPassword",
},
"booking/app/controllers.Hotels.SaveSettings": {
98: "verifyPassword",
100: "verifyPassword",
},
"booking/app/models.(*Hotel).Validate": {
19: "hotel.Name",
21: "hotel.Address",
26: "hotel.City",
32: "hotel.State",
38: "hotel.Zip",
44: "hotel.Country",
},
"booking/app/models.(*User).Validate": {
28: "user.Username",
36: "user.Name",
},
"booking/app/models.Booking.Validate": {
34: "booking.User",
35: "booking.Hotel",
36: "booking.CheckInDate",
37: "booking.CheckOutDate",
39: "booking.CardNumber",
41: "booking.NameOnCard",
},
"booking/app/models.ValidatePassword": {
44: "password",
},
}
这里注册了所有的验证器,并且标记了所有调用验证器`Validation`方法的地方,包括行号以及传入的变量名。
**注册测试用例**
模板:
revel.TestSuites = []interface{}{ {{range .TestSuites}}
(*{{index $.ImportPaths .ImportPath}}.{{.StructName}})(nil),{{end}}
}
渲染后:
revel.TestSuites = []interface{}{
(*tests.ApplicationTest)(nil),
}
这里仅注册当前项目的测试用例。
最后一行,`revel.Run(*port)` 开启服务器监听,运行server。
Go Revel - main函数分析的更多相关文章
- RT-thread main函数分析
RT-thread系统的main函数位于startup.c文件中. /** * This function will startup RT-Thread RTOS. */ void rtthread_ ...
- Tomcat启动分析(一)-从脚本到main函数分析
当我们在Linux下启动tomcat的时候,通过ps查看其进程信息为,接下来的内容我们就以此进行分析: [tomcat@fdd ~]$ ps -ef |grep java tomcat : tty1 ...
- SequoiaDB 系列之五 :源码分析之main函数
好久好久没有写博客了,因为一直要做各种事,工作上的,生活上的,这一下就是半年. 时光如梭. 这两天回头看了看写的博客,感觉都是贻笑大方. 但是还是想坚持把SequoiaDB系列写完. 初步的打算已经确 ...
- Atitit main函数的ast分析 数组参数调用的ast astview解析
Atitit main函数的ast分析 数组参数调用的ast astview解析 1.1. Xxcls.main(new String[]{"","bb"}) ...
- 性能测试分享: Jmeter的源码分析main函数参数
性能测试分享: Jmeter的源码分析main函数参数 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大 ...
- 大数据学习之Scala中main函数的分析以及基本规则(2)
一.main函数的分析 首先来看我们在上一节最后看到的这个程序,我们先来简单的分析一下.有助于后面的学习 object HelloScala { def main(args: Array[String ...
- Keil开发的ARM程序main函数之前的汇编分析
Keil开发的ARM程序main函数之前的汇编分析 ——BIN文件中RW段的数据移动 系统平台: STM32系列STM32F103ZE,512KB内部FLASH,64KB片内存储; FLASH地址范围 ...
- 魔兽世界服务器Trinitycore分析二:auth server的main函数
TrinityCore由生成两个运行文件authserver和world server以及一堆DLL(或so)文件的子项目组成(先忽略map_extractor等几个工具项目). authserver ...
- ffmpeg源码分析二:main函数和transcode函数 (转2)
原帖地址:http://blog.csdn.net/austinblog/article/details/24804455 首先从main函数看起,关键解释部分已加注释,该函数在ffmpeg.c文件中 ...
随机推荐
- angularjs框架及其生态环境 --待续
angular的MVVM框架结构: 1. app, 2.routes, config, 3.module, 4.Controller, $scope,controller参数,事件 ...
- php file_get_contents读取大容量文件方法
当我们遇到文本文件体积很大时,比如超过几十M甚至几百M几G的大文件,用记事本或者其它编辑器打开往往不能成功,因为他们都需要把文件内容全部放到内存里面,这时就会发生内存溢出而打开错误,遇到这种情况我 ...
- 【转】在一个Job中同时写入多个HBase的table
在进行Map/Reduce时,有的业务需要在一个job中将数据写入到多个HBase的表中,下面是实现方式. 原文地址:http://lookfirst.com/2011/07/hbase-multit ...
- HTTP报文头Accept和Content-Type总结
1.Accept属于请求头, Content-Type属于实体头. Http报头分为通用报头,请求报头,响应报头和实体报头. 请求方的http报头结构:通用报头|请求报头|实体报头 响应方的http报 ...
- 《Java Concurrency》读书笔记,使用JDK并发包构建程序
1. java.util.concurrent概述 JDK5.0以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent包中,是专门用于多线并发编程的,充分利用了现代多处 ...
- SQL SERVER 的排序规则
有时候查询数据库的时候会发现(比如做重名检查的时候):数据库的查询时对大小写不敏感的,也就是 A 和 a 是一样的. 也就是说 select * from tabletest where name = ...
- LeetCode OJ 之 Maximal Square (最大的正方形)
题目: Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and ...
- 【问题跟踪】KryoException: java.io.IOException: No space left on device
今天在对LDA进行不同參数训练模型.记录其avglogLikelihood和logPerplexity,以便推断模型训练是否收敛时,产生了一个令人极度崩溃的事儿:程序在辛辛苦苦跑了7.3h后...挂了 ...
- python virtualenv使用
1.什么是virtualenv virtualenv用来做环境隔离,比如项目A使用了python2,项目B使用了python3 使用virtualenv可以分别生成项目A和项目B的环境包 2.virt ...
- VirtualBox虚拟机网络环境解析和搭建-NAT、桥接、Host-Only、Internal、端口映射
一.NAT模式 特点: 1.如果主机可以上网,虚拟机可以上网 2.虚拟机之间不能ping通 3.虚拟机可以ping通主机(此时ping虚拟机的网关,即是ping主机) 4.主机不能ping通虚拟机 应 ...