neve-core是neve的核心组件,实现基于反射的依赖注入框架以及注册bean的生命周期管理,同时提供一套事件处理框架。
go get github.com/xfali/neve-core
目前支持配置文件初始化:
app := neve.NewFileConfigApplication("assets/application-test.yaml")
在application-test.yaml中配置示例如下:
neve:
application:
name: Neve test application
banner: "banner.txt"
bannerMode: off
quit:
sleepSec: 5
inject:
disable: false
workers: 1
userdata:
value: "this is a test"
gopath: {{ env "GOPATH" }}
- 【neve.application.name】应用名称
- 【neve.application.banner】banner文件路径
- 【neve.application.bannerMode】如果设置为off则关闭显示banner
- 【neve.application.eventMode】如果设置为off则禁用内置事件处理框架
- 【neve.inject.disable】是否关闭注入功能,默认false,即开启依赖注入
- 【neve.inject.workers】并行注入的任务数,目前还未开放故默认为1
- 【userdata】非内置配置属性,属于用户自定义的value,可自定义名称
- 配置可使用{{ env "ENV_NAME" DEFAULT_VALUE }}或{{.Env.ENV_NAME}}获取环境变量的值,在读取时进行替换(规则见fig)。
- 直接注册:RegisterBean
- 按名称注册:RegisterBeanByName
app.RegisterBean(processor.NewValueProcessor())
app.RegisterBean(&aImpl{v: "0"})
app.RegisterBeanByName("b", &bImpl{})
// 可以用下述方式快速抛出错误
neverror.PanicError(app.RegisterBean(&aImpl{v: "0"}))
neverror.PanicError(app.RegisterBeanByName("b", &bImpl{}))
neve在注册时可以添加配置参数,目前支持的配置参数有
- order:影响注入的顺序(按从小到大排序,默认为0),同时也影响调用BeanAfterSet回调的顺序。
app.RegisterBean(NewBean(), bean.SetOrder(2))
注意在注册和注入时名称都不可包含逗号“,”
- interface(接口):neve会自动选择实现对象注入或按指定名称注入
- struct Pointer(结构体指针):neve选择具体注册的结构体对象进行注入
- slice:neve可按名称注入slice,也可以自动查询所有适配的对象添加到slice中
- map:neve可按名称注入map,也可以自动查询所有适配的对象添加到map中
注意注入的field首字母需大写(Public)
- 当inject的value为空时自动选择注入
- 当inject的value不为空时则按名称注入
type injectBean struct {
A a `inject:""`
B a `inject:"b"`
BS *bImpl `inject:"b"`
Bf a `inject:"c"`
}
可自定义tag,方法如下:
app := neve.NewFileConfigApplication("assets/application-test.yaml",
neve.OptSetInjectTagName("Autowired"))
type injectBeanB struct {
A a `Autowired:""`
B a `Autowired:"b"`
BS *bImpl `Autowired:"b"`
Bf a `Autowired:"c"`
}
使用tag注入,当注入失败时默认会触发panic,可以通过添加“omiterror”field来忽略注入错误,避免panic。
type injectBean struct {
A a `inject:",omiterror"`
BS *bImpl `inject:"b,omiterror"`
}
neve除了tag注入之外也支持方法注入。相较于tag注入,方法注入可以避免field公开。
step 1: 定义一个类型,类型实现appcontext.InjectFunction接口(即包含方法RegisterFunction(registry appcontext.InjectFunctionRegistry) error), 在接口中将注入的目标方法注册到InjectFunctionRegistry中
type funcBean struct {
as []a
a *aImpl
b *bImpl
}
// 实现接口
func (f *funcBean) RegisterFunction(registry appcontext.InjectFunctionRegistry) error {
return registry.RegisterInjectFunction(func(as []a, a *aImpl, b *bImpl) {
f.as = as
f.a = a
f.b = b
})
}
指定名称注入可以在注册注入方法时指定注入的名称:
registry.RegisterInjectFunction(func(as []a, a a, b *bImpl) {
f.as = as
f.a = a
f.b = b
}, "", "a", "")
step 2: 注册该实例
app.RegisterBean(&funcBean{})
neve会自动检测并将对象通过调用注册的注入方法进行注入。
- 方法的参数注入规则同tag注入的注入规则;
- 方法注入的调用在所有bean完成初始化之后,在调用BeanAfterSet之前。
- 方法注入失败时默认会触发panic,通tag注入一样,可以通过名称中增加“omiterror”忽略错误:
err = registry.RegisterInjectFunction(func(r io.Reader, w io.Writer) {
}, "reader,omiterror", "writer,omiterror")
- 注入struct Pointer时,名称必须完全匹配:
- 如注册时使用RegisterBeanByName方法,则inject的tag value必须与注册时的name完全匹配,否则无法注入。
- 如注册时使用RegisterBean方法,则inject的tag value必须为空,否则无法注入。
- 注入interface时:
- 如注册时使用RegisterBeanByName方法,则inject的tag value必须与注册时的name完全匹配,否则无法注入。
- 如注册时使用RegisterBean方法,则inject的tag value应为空,neve会自动匹配实现interface的对象进行注入。
- 如注册时使用RegisterBeanByName方法且inject的tag value为空,则不会注入该对象。
Processor为注册对象处理器,可对注册对象进行分类和处理。
具体参见Processor
内置的Processor有
- ValueProcessor(值注入处理器),负责将配置文件中的属性值注入到对象:
注意注入的field首字母需大写(Public)
app.RegisterBean(processor.NewValueProcessor())
app.RegisterBean(&bImpl{})
type bImpl struct {
V string `fig:"userdata.value"`
}
注入的tag默认为fig,可以通过下述方法修改:
// 将tag修改为value
app.RegisterBean(processor.NewValueProcessor(processor.OptSetValueTag("", "value")))
err = app.RegisterBean(&bImpl{})
type bImpl struct {
V string `value:"userdata.value"`
}
- neve-web neve的WEB扩展组件,用于集成WEB相关服务。
- neve-database neve的数据库扩展组件,用于集成数据库相关操作。
注册的对象可以实现下述方法监听容器中的bean生命周期:
type Initializing interface {
// 当初始化和注入完成时回调
BeanAfterSet() error
}
type Disposable interface {
// 进入销毁阶段,应该尽快做回收处理并退出处理任务
BeanDestroy() error
}
-
BeanAfterSet (仅调用一次):
在bean完成对象及值注入之后,Processor的Process之前调用,可以做一些初始化相关的工作,此时从配置文件中的Value已经可以读取。
-
BeanDestroy (仅调用一次):
在Application即将退出时调用。
实现SetApplicationContext(ctx ApplicationContext)方法,在bean注入之前即可获取ApplicationContext的引用
type aware struct {
t *testing.T
}
func (a *aware) SetApplicationContext(ctx appcontext.ApplicationContext) {
if ctx == nil {
a.t.Fatal("must not be nil")
}
a.t.Log(ctx.GetApplicationName())
}
neve提供了事件处理框架,包含事件发布器及事件监听器。
neve通过ApplicationEventPublisher发布事件,常用的事件发布方法有两种
获得ApplicationContext,通过获得ApplicationContext的PublishEvent方法发布事件
appCtx.PublishEvent(newCustomerEvent("hello world"))
neve默认会把内置的事件发布器注册到bean容器中,可以通过注入的方式获得ApplicationEventPublisher:
type TestBean struct {
Publisher appcontext.ApplicationEventPublisher `inject:""`
}
// 发布事件
testBean.Publisher.PublishEvent(newCustomerEvent("hello world"))
有如下多种方式注册事件监听器
app.AddListeners(o)
appCtx.AddListeners(o)
该方法支持注册
- 实现ApplicationEventListener的对象
- 方法,该方法的参数为ApplicationEvent或实现ApplicationEvent的对象
type listener3 struct {
t *testing.T
}
// 实现ApplicationEventConsumer接口
func (l *listener3) RegisterConsumer(registry appcontext.ApplicationEventConsumerRegistry) error{
return register.RegisterApplicationEventConsumer(l.handlerEvent)
}
// 当事件为*customerEvent类型时自动匹配并调用该方法
// customerEvent需实现ApplicationEvent接口
func (l *listener3) handlerEvent(event *customerEvent) {
l.t.Log("listener3", event.payload)
}
step 1: 定义一个类型,包含一个获取payload的方法,如getPayload
func (l *listener) getPayload(payload a) {
if payload.Get() != "hello world2" {
l.t.Fatal("not match")
}
l.t.Log("listener", payload.Get())
}
step 2: 注册PayloadEventListener
app.RegisterBean(appcontext.NewPayloadEventListener(l.getPayload))
step 3: 发布一个PayloadApplicationEvent,参数中的对象会被自动匹配并调用PayloadEventListener关联的方法
appContext.PublishEvent(appcontext.NewPayloadApplicationEvent(&aImpl{v: "hello world2"}))
neve注册和注入默认为单例,可以通过注册func() TYPE函数的方式,选择返回单例或者多例。
app.RegisterBean(func() a {
return &bImpl{V: "hello world"}
})
app.RegisterBeanByName("c", func() a {
return &bImpl{V: "hello world"}
})
自版本 v0.2.7 开始已支持注册带参数的function,参数为该方法依赖的被neve管理的对象(已注册到neve)。
// 注意参数a *aImpl,在调用该方法获得对象实例时会自动注入已被neve管理的*aImpl实例。
app.RegisterBeanByName("d", func(a *aImpl) a {
return &bImpl{V: a.v}
})
注意:通过注册function返回的实例无法使用tag方式注入对象,仅通过参数方式注入 当注入产生循环依赖时会抛出panic,类似:
BeanDefinition: [Function] inject type [github.com.xfali.neve-core.test.bImpl] Circular dependency
function返回的对象的生命周期管理方式与普通bean生命周期一致: 通过实现Initializing、Disposable接口进行初始化及资源回收。