gspring
介绍
go语言中的spring框架,实现ioc容器,控制反转,依赖注入。帮助程序员管理bean,在一定程度上解放程序员
软件架构
- 使用抽象类的思想,大量使用模板方法模式编程,例如:AbstractApplicationContext
- 使用注解思想,大量使用接口继承的方式配合tag功能实现注解功能,例如:Initialize
安装教程
- 下载并安装gspring:
$ go get gitee.com/hongzhaomin/gspring
- 将gspring引入到代码中:
import "gitee.com/hongzhaomin/gspring"
使用说明
- 快速开始:
package main
import (
"gitee.com/hongzhaomin/gspring"
"gitee.com/hongzhaomin/gspring/annotation"
)
func main() {
// 启动gspring容器
gspring.Refresh(new(BeanA), new(BeanB))
}
type BeanA struct {
annotation.Component
}
type BeanB struct {
annotation.Component
}
- 一个结构体要想被gspring识别并管理,该结构体必须满足的条件:
package main
import (
"gitee.com/hongzhaomin/gspring"
"gitee.com/hongzhaomin/gspring/annotation"
)
// ======================= Bean定义 ========================
// 结构体必须满足的条件
// 1、结构体内嵌 annotation.Component 可被识别,并且可以添加tag[value]定义bean名称
type TestBean1 struct {
annotation.Component `value:"testBean1"`
}
// 或者
// 2、结构体内嵌 annotation.Configuration 可被识别,并且可以添加tag[value]定义bean名称;
// 可以添加属性testBean3,通过tag[@Bean]注入TestBean3到gspring容器,而 TestBean3 不需要内嵌 annotation.Component 也能被识别,
// 另外,tag值[TestBean3]即为TestBean2的方法名称,用来构建TestBean3对象,同时[TestBean3]的首字母小写即为注入TestBean3的bean名称
type TestBean2 struct {
annotation.Configuration `value:"testBean2"`
testBean3 byte `@Bean:"TestBean3"`
}
func (my TestBean2) TestBean3() TestBean3 {
return TestBean3{}
}
type TestBean3 struct {}
// 或者
// 3、结构体内嵌 annotation.ScanStructField 可被识别,并且可以添加tag[value]定义bean名称;
// 可以添加属性testBean5,它会被自动扫描到,并解析[TestBean5]是否会被gspring容器管理
type TestBean4 struct {
annotation.ScanStructField `value:"testBean4"`
testBean5 TestBean5
}
type TestBean5 struct {
// 采用第三种方式注册,必须要内嵌 annotation.Component 或 annotation.Configuration 或 annotation.ScanStructField
// 才能被gspring容器识别并管理
//annotation.ScanStructField // 优先级第一
//annotation.Configuration // 优先级第二
annotation.Component // 优先级第三
}
// ======================= Bean注册 ========================
// 满足gspring容器管理的条件后,还需要注册,才能被管理:
type TestBean6 struct {
annotation.Component
}
// 第一种注册方式:
func init() {
gspring.Register(new(TestBean6))
}
// 第二种注册方式:
func main() {
gspring.Refresh(new(TestBean6))
}
- gspring提供依赖注入的功能
-
使用tag@Resource
方式实现普通属性的依赖注入,@Resource
的值表示需要注入的bean名称,不写会以属性名称的首字母小写形式作为bean名称注入;
注意:
1、需要注入的属性类型仅支持结构体指针、接口、对象切片、对象切片指针类型
2、@Resource
优先根据属性类型注入,然后再根据bean名称注入
-
使用tag@Extends
方式实现内嵌属性的依赖注入,@Extends
的值表示需要注入的bean名称,不写会以属性类型名称的首字母小写形式作为bean名称注入;
注意:同 @Resource
-
使用tag@Value
方式实现基本类型的普通属性的依赖注入,@Value
的值为${xxx}
格式的表达式,它会从gspring的环境配置文件中取值注入;
注意:
1、被 @Value
标记的属性类型仅支持基本类型,例如:string、int、int64、bool等等
2、@Value
的值为 ${xxx}
格式的表达式,例如:${server.port:8080}
,该表达式表示如果server.port
在环境配置中取不到值则取默认值8080
,
如果改为 ${server.port}
,则 server.port
取不到值会panic启动报错
package main
import (
"gitee.com/hongzhaomin/gspring"
"gitee.com/hongzhaomin/gspring/annotation"
)
// 1、普通属性使用 @Resource 注入
// 优先根据 *TestBean2 类型注入,然后再根据名称 testBean2 注入
type TestBean1 struct {
annotation.Component
// 如果将 @Resource:"testBean2" 改为 @Resource:"",
// 则需要根据名称注入时,会使用 testBean 作为bean名称
TestBean *TestBean2 `@Resource:"testBean2"`
}
type TestBean2 struct {
annotation.Component
}
// 2、内嵌属性使用 @Extends 注入
// 优先根据 *TestBean2 类型注入,然后再根据名称 testBean2 注入
type TestBean3 struct {
annotation.Component
// 如果将 @Extends:"testBean2" 改为 @Extends:"",
// 则需要根据名称注入时,会使用 testBean2(TestBean2名称首字母小写形式) 作为bean名称
*TestBean2 `@Extends:"testBean2"`
}
// 3、普通基础类型属性使用 @Value 注入
type TestBean4 struct {
// @Value的值不能省略,且要符合表达式 ${xxx} 形式
ServerPort int `@Value:"${server.port:8080}"`
}
- 关于注入有一个特殊的点,由于go语言的特性,gspring额外支持了内嵌结构体或内嵌接口的自动注入,
此种情况的内嵌结构体会进一步读取其属性,并进行依赖注入。如果该内嵌属性为接口类型,会将当前bean实例注入到该内嵌接口属性中,
这样实现的目的是为了方便利用gspring构建抽象类,实现模板方法模式
package main
import (
"fmt"
"gitee.com/hongzhaomin/gspring"
"gitee.com/hongzhaomin/gspring/annotation"
)
func main() {
// 利用gspring实现抽象类的模板方法模式
gspring.Refresh(
new(Teacher),
new(Student),
)
stu := gspring.GetBean[Student]()
stu.Main() // 我是一个老师 我是一个男人
tea := gspring.GetBean[Teacher]()
tea.Main() // 我是一个学生 我是一个男人
}
// 定义一个 Person 接口
type Person interface {
Main()
Name() string
Sex() string
}
// 定义一个Person抽象类,只实现了Main和Sex方法
type AbstractPerson struct {
Person
}
func (my AbstractPerson) Main() {
fmt.Println(my.Name(), my.Sex())
}
func (my AbstractPerson) Sex() string {
return "我是一个男人"
}
// 定义一个 Teacher 老师对象,内嵌 AbstractPerson,实现Name方法
type Teacher struct {
annotation.Component
// 注意不能使用 @Extends,否则就不能达到效果
AbstractPerson
}
func (my *Teacher) Name() string {
return "我是一个老师"
}
// 再定义一个 Sutdent 学生对象,内嵌 AbstractPerson,实现Name方法
type Student struct {
annotation.Component
// 注意不能使用 @Extends,否则就不能达到效果
AbstractPerson
}
func (my Student) Name() string {
return "我是一个学生"
}
- 一个被gspring管理的bean,可以扩展初始化方法:
package main
import (
"fmt"
"gitee.com/hongzhaomin/gspring/annotation"
)
// 第一种方式(优先):使用 [annotation.Initialize] 注解的方式,实现 Init() 方法
type TestBean1 struct {
annotation.Component
annotation.Initialize
}
func (my *TestBean1) Init() {
fmt.Println("TestBean1 ==> 执行初始化方法(Init)")
}
// 第二种方式:使用 annotation.Component、annotation.Configuration、annotation.ScanStructField 的tag[initMethod]指定
// 注意:
// 1、initMethod 指定的方法必须为可导出的
// 2、DoInit方法必须是无参且无返回值的方法
type TestBean2 struct {
annotation.Component `initMethod:"DoInit"`
}
func (my *TestBean2) DoInit() {
fmt.Println("TestBean2 ==> 执行初始化方法(DoInit)")
}
- 基于gspring的扩展:
- aware接口的扩展,目前支持两种aware接口:
BeanFactoryAware
和 BeanNameAware
以 BeanFactoryAware
作为一个示例
package main
import (
"gitee.com/hongzhaomin/gspring/annotation"
"gitee.com/hongzhaomin/gspring/aware"
"gitee.com/hongzhaomin/gspring/iface"
)
type TestBean struct {
annotation.Component
aware.BeanFactoryAware
beanFactory iface.BeanFactory
}
func (my *TestBean) SetBeanFactory(beanFactory iface.BeanFactory) {
my.beanFactory = beanFactory
}
BeanPostProcessor
接口的扩展,源码中 CommonAnnotationBeanPostProcessor
就是一个应用示例,针对Bean的增强器
BeanFactoryPostProcessor
接口的扩展,源码中 StructPointResolvedPostProcessor
就是一个应用示例,针对BeanFactory的增强器
-
Environment
接口的实现,这个接口的实现对第三点依赖注入中提到的 @Value
注入至关重要, 因为 @Value
中注入的值的来源,依赖此接口。所以需要实现该接口后,交给gspring容器管理。
-
todo
参与贡献
- Fork 本仓库
- 新建 Feat_xxx 分支
- 提交代码
- 新建 Pull Request
特技
- 使用 Readme_XXX.md 来支持不同的语言,例如 Readme_en.md, Readme_zh.md
- Gitee 官方博客 blog.gitee.com
- 你可以 https://gitee.com/explore 这个地址来了解 Gitee 上的优秀开源项目
- GVP 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
- Gitee 官方提供的使用手册 https://gitee.com/help
- Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 https://gitee.com/gitee-stars/