我们都知道,一个应用一般会用到很多的配置项以及展视用的视图模板,这些配置项和模板文件经常需要变动,如果每次改动都需要重启服务甚至是重新编译,明显是不合理的,本篇介绍一下怎么动态重新加载新的配置项和模板。
框架对象及生命周期
先来了解一下框架对象和它的生命周期,学过ASP的人都知道(是否暴露年龄了?),ASP里有几个内置对象,其中包括Application和Session.
Application对象是服务全局对象,而Session是会话对象,我在框架中也使用了类似的思想,使用Application结构来表示全局对象,用来保存服务从启动到结束的相关内容。而使用Request结构表示一次请求从到达到处理完成的相关内容(即单次会话)。
本篇所提到的配置内容和模板,都属于Application,即全局内容,其生命周期是从启动服务器开始生成,到服务器结束后消亡。
理解这一点,就很容易处理配置和模板的动态加载了。
app := &Application{
conf: LoadConf(), //载入配置到全局对象的属性
viewTemplates: buildTemp(), //载入模板到全局对象
//其它全局属性
}
全局配置和模板的动态重载
动态重载,实际上是重新读取配置和模板,然后赋值到app的相应属性即可。
要解决的问题是重新读取的时机,我选择了在reqFinish()时使用goroutine处理.
如果每次请求都重新读取和重编译模板,代价有点大,这里采取了一些手段来减轻无谓的处理:
-
对于配置文件,判断文件是否有修改(根椐每次读取时记录的最新读取时间和文件修改时间来比较),有修改才读取
-
对于模板,因为有include子模板的情况(即虽然主模板没变,但因为子模板变了主模板也要重新生成),采取的是扫描全部模板文件,如果任意文件有发生变化,则全部重新生成模板。
这样,每次请求后,都会去检查是否有配置文件或模板文件的修改(包括新增模板文件),如有,则读取重新赋值到全局对象属性,实现动态热加载。
当然,大并发下,如果大量请求都在检查,这对系统资源肯定是一种极大的浪费,同时会造成冲突甚至异常,可以通过加锁的方式解决,保证同一时间只有一个任务在检查。