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文件中 ...
随机推荐
- java操作redis。jedis使用api
package com.wujintao.redis; import java.util.Date; import java.util.HashMap; import java.util.Iterat ...
- 条件触发和边缘触发 及 epoll 的长处
条件触发: 仅仅要输入缓冲有数据就会一直通知该事件 边缘触发: 输入缓冲收到数据时仅注冊1次该事件.即使输入缓冲中还留有数据,也不会再进行注冊 水平触发(level-triggered.也被称为条件触 ...
- FreeSWITCH呼叫参数之sip_cid_type
这个参数定义了呼叫中主叫信息的头字段类型.支持两种类型: 1. rpidRemote-Party-ID头,这是默认的设置.{sip_cid_type=rpid}sofia/default/user@e ...
- HMM条件下的 前向算法 和 维特比解码
一.隐马尔科夫HMM如果: 有且仅仅有3种天气:0晴天.1阴天.2雨天 各种天气间的隔天转化概率mp: mp[3][3] 晴天 阴天 雨天 晴天 0.33333 0.33333 0.33333 阴天 ...
- 创建多模块springcloud应用eureka server和client和消费端demo
使用环境是 STS + maven 1 创建父级 项目,springcloud-demo1 new -> maven project -> 按照要求进行配置即可.然后删除 src目录,因为 ...
- android 通过命令行启动Apk
几个启动指定程序activity的例子 Music 和 Video(音乐和视频)的启动方法为: # am start -n com.android.music/com.android.music.Mu ...
- .NET MVC EF框架数据库连接配置
1:数据库的配置和连接 Web.config <connectionStrings> <add name="SQLConnectionString" connec ...
- (原创)c++11改进我们的模式之改进代理模式,实现通用的AOP框架
c++11 boost技术交流群:296561497,欢迎大家来交流技术. 本次要讲的时候如何改进代理模式,具体来说是动态代理模式,动态代理模式一般实现AOP框架,不懂AOP的童鞋看这里.我前面的博文 ...
- Android 编程下 Managing Your App's Memory
Managing Your App's Memory Random-access memory (RAM) 在任何软件开发环境中都是宝贵的资源,它在物理内存有限的移动操作系统中更为宝贵.虽然 Andr ...
- Silverlight-MEF-DEMO
“托管扩展性框架(Managed Extensibility Framework,简称MEF),是微软.NET框架下为提高应用和组件复用程度而推出的,用于使组件能够最大化的重用.使用MEF能够使静态编 ...