欢迎进入Wiki » FAQ » 应用与插件自动升级机制说明?

应用与插件自动升级机制说明?

在2015-08-08 19:04上被李小翔修改
评论 (0) · 附件 (0) · 记录 · 信息

供稿人:张文秀

插件或应用更新后,经常需要修改老的数据或数据库结构、新增基础数据(如配置、数据字典)等,部署到服务器时,为了实现自动化升级,我们通常在 XxxxBootStrap.groovy 中实现数据的升级,但是,通过 BootStrap 升级存在下面的问题:

  1. 运行时间晚于 Grails 的数据库结构升级,因此,无法提前对数据进行预处理
  2. 升级代码需要写很多判断条件(如XX不存在、则新增XX),影响每次启动性能
  3. 升级代码容易变得过长,不易维护
  4. 升级代码的版本不好控制
  5. 如果中间升级失败,不易回滚、定位、重新执行

因此,在 BroFramework 中,新增了一种 Updater 的 Artefact,用于编写代码自动升级;并且将每次升级的插件名、应用名、版本号、升级成功与否等信息记录在数据表 brofwk_update_log 中。

以插件 BroBPM 为例,插件的 grails-app\conf\ 目录下有一个 update 文件夹,包下有多个前缀为 “Updater” 的 groovy 文件,分别是 UpdaterXXXInitiator 和 UpdaterXXX,升级的代码主要写在这些文件。

此外,子文件夹 resource 下面又存放了一些脚本,这些脚本会在 UpdaterXXXInitiator 和 UpdaterXXXX 中被调用执行;这些资源并不是必要的,而是根据情况自行添加、调用。

除了类名前缀外,这些升级器类的属性、方法规范如下面的模板所示:

class UpdaterXxxx {

   def initiator = true/false
   
   def version = "4.1.0.92940"
   
   def pluginName = "broBpm"
   
   def description = "......"

   def beforeDbUpdate( Sql sqlInst, String dbName, String dbSchema ) {
      ....
   }
   
   def beforeDbUpdate_auditlog( Sql sqlInst, String dbName, String dbSchema ) {
       ....
   }
   
   def beforeBootStrap() {
       ....
   }
   
   def afterBootStrap() {
       ....
   }
   
}

属性:

  • initiator:是否为始化版本
    每个应用或插件中只允许有一个 true 的升级器,类名我们通常命名为 UpdaterXXXInitiator,该升级器中主要是一些基础数据初始化代码,并且只是在应用第一次启动的时候执行一次,之后启动就不会再执行。
  • version:升级器的版本号
    格式为不超过四段的数字,如 w.x.y.z、x.y,前三段每段最多3个字符、最后一段最多10个字符,共22个字符。
    目前版本号组成是插件自己的版本号+svn版本号,假如你做了一个新功能,在升级的时候需要初始化一个新的系统参数,比如BPM的版本是4.1.0,提交了代码之后查看svn版本是92940,此时UpdaterXXX版本号就要更新为 4.1.0. 92940。
    版本号是-1 时则禁用,需要注意的是,如果修改了升级器类,则必须升级 version,否则新的升级代码在启动时不会被执行的。
  • pluginName:插件名称
    默认为 app_应用名,即不属于任何插件
  • description:升级器描述

事件:

  • beforeDbUpdate( Sql sqlInst, String dbName, String dbSchema )
    在 Grails 自动更新数据库表结构前执行的。
    此方法支持多数据源,beforeDbUpdate 表示更新默认数据源,beforeDbUpdate_auditlog 表示更新名为 auditlog 的数据源,这个是和dataSource中数据源的配置是类似的。
    参数Sql sqlInst已初始化的数据库连接,用来执行sql;参数String dbName数据库名称,如数据库是oracle则这个参数的值是oracle,因为不同数据库的sql有差异,通过这个参数就可以判断不同数据库的时候执行不同的sql;参数String dbSchema数据库名,用于拼sql,如表名前缀:select * from ${dbSchema}.abc
  • beforeBootStrap()
    在所有的 BootStrap 类和 bootStrapInit 方法之前执行
  • afterBootStrap()
    在所有的 BootStrap 类和 bootStrapInit 方法之前执行

下面是一个初始化升级器的示例:

package update

class UpdaterAppInitiator {
   def initiator = true
   def version = "1.0.0.1234"
   def description = "初始化应用 Foobar,版本 1.0"
   
   def settingService
   
   def beforeBootStrap() {
        settingService.create("foobar.foo.bar", ....).save()
       ....
   }
}

下面是一个非初始化的升级器的示例:

package update

class UpdaterApp11 {

   def version = "1.1.0.12345"
   def description = "版本 1.0 到 1.1 的升级器"
   
   def beforeDbUpdate( Sql sqlInst, String dbName, String dbSchema ) {
       try {
           if ( dbName == "oracle" ) {
                sqlInst.executeUpdate("ALTER TABLE ...")
           } else {
                sqlInst.executeUpdate("ALTER TABLE ...")
           }
       } catch(Exception e) {}
   }
   
   def beforeDbUpdate_xxxx( Sql sqlInst, String dbName, String dbSchema ) {
       ....
   }
   
   def beforeBootStrap() {
       if ( Xxxx.countByXX() == 0 ) {
           new Xxxx(....).save()
       }
       if ( .... ) {
           ....
       }
   }
   
}
标签: BroFramework
在2015-08-08 19:04上被李小翔创建

Copyright © 2013 北京博瑞开源软件有限公司
京ICP备12048974号