gspring

package module
v0.0.0-...-af198dd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2025 License: Apache-2.0 Imports: 7 Imported by: 3

README

gspring

介绍

go语言中的spring框架,实现ioc容器,控制反转,依赖注入。帮助程序员管理bean,在一定程度上解放程序员

软件架构
  1. 使用抽象类的思想,大量使用模板方法模式编程,例如:AbstractApplicationContext
  2. 使用注解思想,大量使用接口继承的方式配合tag功能实现注解功能,例如:Initialize
安装教程
  1. 下载并安装gspring:
$ go get gitee.com/hongzhaomin/gspring
  1. 将gspring引入到代码中:
import "gitee.com/hongzhaomin/gspring"
使用说明
  1. 快速开始:
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
}
  1. 一个结构体要想被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))
}

  1. 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}"`
}
  1. 关于注入有一个特殊的点,由于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 "我是一个学生"
}
  1. 一个被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)")
}
  1. 基于gspring的扩展:
  • aware接口的扩展,目前支持两种aware接口:BeanFactoryAwareBeanNameAware

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的增强器
  1. Environment 接口的实现,这个接口的实现对第三点依赖注入中提到的 @Value 注入至关重要, 因为 @Value 中注入的值的来源,依赖此接口。所以需要实现该接口后,交给gspring容器管理。

  2. todo

参与贡献
  1. Fork 本仓库
  2. 新建 Feat_xxx 分支
  3. 提交代码
  4. 新建 Pull Request
特技
  1. 使用 Readme_XXX.md 来支持不同的语言,例如 Readme_en.md, Readme_zh.md
  2. Gitee 官方博客 blog.gitee.com
  3. 你可以 https://gitee.com/explore 这个地址来了解 Gitee 上的优秀开源项目
  4. GVP 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
  5. Gitee 官方提供的使用手册 https://gitee.com/help
  6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 https://gitee.com/gitee-stars/

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetBean

func GetBean[T any]() *T

func GetBeanByName

func GetBeanByName[T any](beanName string) T

func GetBeanByType

func GetBeanByType[T any](beanType T) T

func GetBeanIdentity

func GetBeanIdentity[T any]() T

func GetBeans

func GetBeans[T any]() []T

func Refresh

func Refresh(beans ...any) iface.ApplicationContext

func Register

func Register(beans ...any)

Register 将bean注册到gspring容器中,交给gspring管理 在整合其他框架的时候可以将需要交给gspring管理的bean,在init函数中调用此方法注册进来

func SetDefaultCtx

func SetDefaultCtx(ctx iface.ApplicationContext)

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL