From 5f54bf48d86f4f1682f0070d1d5052e7959eb924 Mon Sep 17 00:00:00 2001 From: yuanzhao <2206582181@qq.com> Date: Fri, 16 Aug 2024 18:06:15 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E6=96=B0=E5=A2=9E=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++ console/commands/bean.go | 28 +++++++++++++- docs/bean.md | 84 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 docs/bean.md diff --git a/README.md b/README.md index d6cb8fe..30d257c 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ fmt.Println(user, has, users, count) ## 生成依赖注入_ 这里的原始有点像 `wire` 库, 但是不需要额外声明文件和关系, 而是使用通俗约定地生成源码,具体可以查看生成的文件`z_inject_gen.go` + +具体使用查看 docs 目录 + ````go // Kernel @Bean type Kernel struct { diff --git a/console/commands/bean.go b/console/commands/bean.go index 532d8f0..23203ba 100644 --- a/console/commands/bean.go +++ b/console/commands/bean.go @@ -244,6 +244,9 @@ func getInitializeNewFunName(k parser.GoTypeAttr, m map[string]string) string { got := providers + "GetBean(\"" + beanAlias + "\").(" + providers + "Bean)" if strings.Index(beanValue, "@") != -1 { + // 嵌套时, inject: "@config("app.name")" + // 只支持字符串嵌套注入 + startTemp := strings.Index(beanValue, "(") beanValueNextName := beanValue[1:startTemp] if beanValue[len(beanValue)-1:] != ")" { @@ -252,12 +255,33 @@ func getInitializeNewFunName(k parser.GoTypeAttr, m map[string]string) string { beanValueNextVal := strings.Trim(beanValue[startTemp+1:], ")") got = got + ".GetBean(*" + providers + "GetBean(\"" + beanValueNextName + "\").(" + providers + "Bean).GetBean(\"" + beanValueNextVal + "\").(*string))" } else if tag.Count() <= 2 { - got = got + ".GetBean(\"" + beanValue + "\")" + // 如果没有默认值 + if beanValue == "" { + gotType := "*" + alias + name + + // 如果`inject:""`检查是否实现Bean接口, 没有实现就不调用 + gotFuncStr := `func() {gotType} { + var temp = {providers}GetBean("{beanAlias}") + if bean, ok := temp.({providers}Bean); ok { + return bean.GetBean("").({gotType}) + } + return temp.({gotType}) + }()` + got = strings.ReplaceAll(gotFuncStr, "{providers}", providers) + got = strings.Replace(got, "{beanAlias}", beanAlias, 1) + got = strings.ReplaceAll(got, "{gotType}", gotType) + return got + } else { + // 必然是实现了Bean接口 + got = got + ".GetBean(\"" + beanValue + "\")" + } } else if tag.Count() == 3 { + // 多个参数||有默认值的注入 beanValue = beanValue + ", " + tag.Get(2) got = got + ".GetBean(`" + beanValue + "`)" } - + // 如果被注入的是接口时, 这里的*是多余的, 还不支持注入到 type interface 的变量 + // 如果有需要, 自行复制z_inject_gen.go内代码, 把开头*和类型*删除,就兼容了 return got + ".(*" + alias + name + ")" } } diff --git a/docs/bean.md b/docs/bean.md new file mode 100644 index 0000000..d692aed --- /dev/null +++ b/docs/bean.md @@ -0,0 +1,84 @@ +## Bean 注解 +依赖生成工具 [toolset](https://github.com/go-home-admin/toolset); 每个struct如果存在注解 @Bean 那么它就可以被依赖系统管理, 你可以在任意地方编写以下代码,注解依赖工具[`toolset make:bean`](https://github.com/go-home-admin/toolset "`toolset make:bean`"),这个工具可以运行任意项目下,可以不限制本框架。 + +```go +// @Bean +type Test struct { + TestPort int `inject:"config, app.servers.http.port"` +} +``` +上面代码标识,`Test ` 应该有依赖系统管理,属性TestPort 应获得一个`int`类型的配置。配置由`config`服务提供,参数是 `app.servers.http.port`,`config`服务又是由注解 @Bean("config") 管理,当然它已经在框架引导文件里定义好了,查看 [源码](https://github.com/go-home-admin/home/blob/main/bootstrap/providers/config_provider.go "源码"),你可以参考和定义更强大功能的服务提供者。编写好了,再使用工具生成注释对应的源码。 +```shell +make gen +``` +执行命令后,工具会在对应目录生成`z_inject_gen.go`,这个文件不应该手动维护;`Test `struct 就可以在其他地方使用了,只是手动`NewTest`, 也可以在别的地方使用`inject`注解注入 +```go +func test() { + NewTest() +} +// @Bean +type EchoTest struct { + Test *Test `inject:""` +} +``` +## 动态注入 +为了更模块化开发,通常一个模块都有一个独立配置文件,以方便扩展功能;例如一个支付模块,需要更改自定义的数据库连接,动态注入指定配置的连接 +```go +// @Bean +type Play struct { + DB *gorm.DB `inject:"database, @config(play.connect)"` +} +``` + +## Bean的生命周期 +```go +// @Bean +type DemoBean struct {} + +func (receiver DemoBean) Init() { + // 会在第一次NewDemoBean()时候执行 +} + +func (receiver DemoBean) Boot () { + // 会在框架所有的Init执行后,再统一执行 Boot +} + +func (receiver DemoBean) Exit () { + // 应用退出时候统一执行 Exit +} +``` + +### 接口注入 + +当前为了快速解析语法树, 没有做挎包读取的功能, 所以需要手动编写代码, 去支持注入 + +~~~~go +type FromB interface { + B() +} + +// 注入 b 实现, 是不能直接支持的 +// 这里不要写Bean("a") +type GetB struct { + b FromB `inject:"b"` +} + +var _GetBSingle *GetB + +// 手动编写代码, 去支持注入 +func NewGetB() *GetB { + if _GetBSingle == nil { + _GetBSingle = &GetB{} + _GetBSingle.b = func() FromB { + var temp = providers.GetBean("b") + if bean, ok := temp.(providers.Bean); ok { + return bean.GetBean("").(FromB) + } + return temp.(FromB) + }() + providers.AfterProvider(_GetBSingle, "a") + } + return _GetBSingle +} + +~~~~ \ No newline at end of file