10

OpenResty与模块

 4 years ago
source link: https://www.tuicool.com/articles/FjU7jyn
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Lua 中没有常见面向对象语言中所谓类的概念,取而代之使用模块来组织管理代码。关于模块的基础知识大家可以参考「 OpenResty 最佳实战 」,本文聊点别的。

如何实现一个模块呢?假设我们要实现一个不太安全的房奴模块(houseslave.lua):

local _M = {}


local mt = { __index = _M }


function _M.new(me, bank)
    local t = {
        me = me,
        bank = bank,
    }

    return setmetatable(t, mt)
end


function _M.repay(self, money)
    self.me.money = self.me.money - money
    self.bank.money = self.bank.money + money
end


return _M

如果我们借用类的思维来解释这段代码,那么大概意思就是:类的属性保存在表(t)中,类的方法保存在元表(mt)中,二者通过 setmetatable 关联起来。

实际使用的时候,大致如下所示:

local houseslave = require "houseslave"
local hs = houseslave.new(me, bank)
hs:repay(10000)

学习模块最好的方法就是多看别人是如何搞的,但也不能完全照搬,以很多人都很熟悉的 lua-resty-redis 模块为例,如果通过 luacheck 来检查的话,会发现很多问题:

eAJnEvf.png!web

lua-resty-redis

我们就以 new 方法的问题为例来说明一下, 官方文档 的描述如下:

red, err = redis:new()

通过冒号语法糖,self 参数被隐式传递了,但这不是重点,要紧的是 self 在这里有没有意义?实际上,new 相当于是类里的构造函数,在调用构造函数之前,还没有实例化出对象,此时 self 是多余的,应该去掉 new 参数中 self 的定义,当然调用方式也要改一下:

red, err = redis.new()

如果你没搞清楚,可以多看看前面房奴的例子,体会一下「点」和「冒号」的差异。

OpenResty 通过 package.path 来查找模块,初学者往往不知道应该把自己写的模块放到哪个目录,此时可以通过 resty-cli 工具来确认你的 package.path 设置:

BzEvUnu.jpg!web

package.path

已经装载的模块保存在 package.loaded.* 中,于是我们可以通过 package.loaded.* = nil 的方式卸载对应的模块,如此一来就实现了 热装载代码 ,同把大象放冰箱一样分三步:

  1. 把需要动态加载的代码放在一个 Lua 模块文件 foo.lua 中,并标记版本号。
  2. 暴露一个 location 以便从外部写最新的版本号到一个 ngx_lua 共享内存字典中。
  3. 在 Lua 代码中,首先检查当前 foo 模块的版本号与共享内存字典中的最新版本号是否一致;如果不一致的话,则卸载当前的 foo 模块(package.loaded.foo = nil ),然后再调用 local foo = require “foo”,从而完成热装载代码。

需要说明的是,使用了 LuaJIT FFI 的模块是不能通过清空 package.loaded 中的对应字段卸载的,好在多数时候,需要频繁热装载代码的模块往往是业务相关的模块,我们可以在设计之初,有意识的把 LuaJIT FFI 相关的代码单独剥离出来。

好了,赶在十月底最后一天完成了本月的文章,虽然没什么营养,但习惯不能丢。

ieey22E.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK