go-decorator, 使用注释注入装饰器的 go 语言中间件工具

dengsgo · · 933 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
`go-decorator` 是用于 Go 语言编译器的中间件工具,能够通过注释方式实现非侵入式的装饰器使用。 ## Feature - 使用 `//go:decor decoratorfunctionName` 注释函数即可使用装饰器 `decoratorfunctionName`,快速完成样板代码注入、非侵入式改变函数行为、控制逻辑流程等; - 定义 `func(*decor.Context)` 类型的函数,即可作为装饰器,应用于任意一级函数(top-level function); - 支持使用多个(行)`//go:decor`装饰器来装饰函数; - 提供友好的错误提示,可在编译时发现问题并给出错误原因和错误行号(例如未定义的装饰器或未引用的包等); - 仅在编译时增强目标函数,不会降低编译后程序的性能,也没有反射操作; - 提供基础使用指南。 装饰器的使用场景,可以类比其他语言,比如 Python、TypeScript。(非常适合在缓存、鉴权、日志等场景使用,作为辅助手段解放重复编码的困扰)。 `go-decorator` 是一种编译时装饰器注入技术。使用它不会影响您项目的源文件,并且不会在项目中生成额外的 `.go` 文件或其他冗余文件。这种注入方法与 `go:generate` 生成方式截然不同。 GitHub: <https://github.com/dengsgo/go-decorator> ----------- ## 使用样例 创建一个项目,我们这里module名为 `demo`. 在你的项目引入装饰器依赖(go.mod 项目): ``` $ go mod init $ go get -u github.com/dengsgo/go-decorator ``` ![]()![](<> "点击并拖拽以移动") 创建 `main.go`, 编写如下代码: ``` package main import ( "github.com/dengsgo/go-decorator/decor" "log" ) func main() { // 正常调用你的函数。 // 由于这是一个声明使用装饰器logging的函数, // decorator 编译链会在编译代码时注入装饰器方法logging的调用。 // 所以使用上面的方式编译后运行,你会得到如下输出: // // 2023/08/13 20:26:30 decorator function logging in [] // 2023/08/13 20:26:30 this is a function: myFunc // 2023/08/13 20:26:30 decorator function logging out [] // // 而不是只有 myFunc 本身的一句输出。 // 也就是说通过装饰器改变了这个方法的行为! myFunc() } // 通过使用 go:decor 注释声明该函数将使用装饰器logging来装饰。 // //go:decor logging func myFunc() { log.Println("this is a function: myFunc") } // 这是一个普通的函数 // 但是它实现了 func(*decor.Context) 类型,因此它还是一个装饰器方法, // 可以在其他函数上使用这个装饰器。 // 在函数中,ctx 是装饰器上下文,可以通过 ctx 获取到目标函数的出入参 // 和目标方法的执行。 // 如果函数中没有执行 ctx.TargetDo(), 那么意味着目标函数不会执行, // 即使你代码里调用了被装饰的目标函数!这时候,目标函数返回的都是零值。 // 在 ctx.TargetDo() 之前,可以修改 ctx.TargetIn 来改变入参值。 // 在 ctx.TargetDo() 之后,可以修改 ctx.TargetOut 来改变返回值。 // 只能改变出入参的值。不要试图改变他们的类型和数量,这将会引发运行时 panic !!! func logging(ctx *decor.Context) { log.Println("decorator function logging in", ctx.TargetIn) ctx.TargetDo() log.Println("decorator function logging out", ctx.TargetOut) } ``` ![]()![](<> "点击并拖拽以移动") 然后 `go install` 安装 `decorator` 工具: ``` $ go install github.com/dengsgo/go-decorator/cmd/decorator@latest ``` ![]()![](<> "点击并拖拽以移动") 运行 `decorator`,显示 `decorator` 版本信息即为安装成功。 ``` $ decorator decorator 0.1.0 beta , https://github.com/dengsgo/go-decorator ``` ![]()![](<> "点击并拖拽以移动") `decorator` 是 `go` 的编译链工具,依靠 `go` 命令来调用它运行,进行代码的编译。 所以我们编译代码需要在 `go build` 命令中加入 `-toolexec decorator` 参数。 编译&&运行: ``` $ go build -toolexec decorator $ ./demo ``` ![]()![](<> "点击并拖拽以移动") 会有类似输出打印: ``` 2023/08/13 20:26:30 decorator function logging in [] 2023/08/13 20:26:30 this is a function: myFunc 2023/08/13 20:26:30 decorator function logging out [] ``` ![]()![](<> "点击并拖拽以移动") 说明 `go-decorator` 已经成功加入了编译链,并注入了装饰器。 详细的使用文档可以访问下面的链接: [Guide](https://github.com/dengsgo/go-decorator/blob/master/GUIDE.zh_cn.md) | [Guide 国内Gitee](https://gitee.com/dengsgo/go-decorator/blob/master/GUIDE.zh_cn.md) 项目代码: GitHub: <https://github.com/dengsgo/go-decorator>   有一些大家可能会关心的点,这里也提一下: ## 条件和限制 以下几种情况需要注意: - 使用装饰器的目标函数范围**仅限当前项目内**。依赖的其他库即使使用 `//go:decor`也**无法**被装饰。 例如,你的项目module名称是 `a/b/c` ,那么 `//go:decor` 只在 `a/b/c` 及其子包中生效(`a/b/c/d` 有效,`a/m/`无效)。 但是`//go:decor`可以使用任意包的装饰器,没有范围限制。 - **不能**在同一个目标函数上同时使用相同的装饰器重复装饰; - **不能**对装饰器函数应用装饰器; - 升级 `decorator` 后或者调整编译参数可能需要在 go 命令中追加 `-a` 参数**强制编译**一次,以覆盖旧的编译缓存。 ## 开发与调试 `decorator` 作为 go 编译链中的一环,编译时被 go 编译器加载使用。它与 go 的编译链保持兼容,不会产生副作用。 开发流程中要改变的只是给用到的 go 命令增加 `-toolexec decorator` 参数,其他完全一致,感觉不到有变化。 你也可以随时取消这个参数。放弃项目对 go 装饰器的使用。即使代码中保留了 `//go:decor` 注释也不会有任何副作用(因为它对于标准工具链来说只是无意义的注释而已)。 调试同理。 例如,在 vscode 中,编辑 `launch.json`: ``` { "version": "0.2.0", "configurations": [ { "name": "Launch file", "type": "go", "request": "launch", "mode": "debug", "program": "${file}", "buildFlags": "-toolexec decorator" } ] } ``` ![]()![](<> "点击并拖拽以移动") 添加 `"buildFlags": "-toolexec decorator"` 这一行以启用 `decorator` 的装饰器编译。 然后正常断点调试即可。 > 调试体验会不断完善,如果发现问题请让我知道 [Issues](https://github.com/dengsgo/go-decorator/issues)。 ## 性能 尽管 `decorator` 在编译时会对目标函数做额外的处理,但它仅仅只构建必要的上下文参数,没有额外开销,更没有反射。相对于原始go代码直接调用装饰器函数来讲,性能几乎是一致的。 ## 最后 项目初期,可能会遇到各种各样的问题,随时欢迎 Issues 反馈给我, [Issues](https://github.com/dengsgo/go-decorator/issues) 。 最后最后,强调一下,**现阶段不要将它用于生产环境!现阶段不要将它用于生产环境!现阶段不要将它用于生产环境!** ​

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

933 次点击  ∙  2 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传