Only two weeks after the last release, Go-Spring, the one-stop development framework for Go backend, has released a new version. The new version implements two very important features: dynamic configuration and bean sharing.
Dynamic configuration
Sometimes we want to be able to modify the configuration of the program and change the behavior of the program without downtime, the so-called “dynamic configuration”. Go-Spring implements the same usage as ordinary properties by using special data types. It supports both default values ββand type verification, while also ensuring data concurrency safety, which is very simple and powerful.
type DynamicConfig struct {
Int dync.Int64 `value:"${int:=3}" validate:"$<6"`
Float dync.Float64 `value:"${float:=1.2}"`
Map dync.Ref `value:"${map:=}"`
Slice dync.Ref `value:"${slice:=}"`
Event dync.Event `value:"${event}"`
}
type DynamicConfigWrapper struct {
Wrapper DynamicConfig `value:"${wrapper}"`
}
func TestDynamic(t *testing.T) {
var cfg *DynamicConfig
wrapper := new(DynamicConfigWrapper)
c := gs.New()
c.Provide(func() *DynamicConfig {
config := new(DynamicConfig)
config.Int.OnValidate(func(v int64) error {
if v < 3 {
return errors.New("should greeter than 3")
}
return nil
})
config.Slice.Init(make([]string, 0))
config.Map.Init(make(map[string]string))
config.Event.OnEvent(func(prop *conf.Properties) error {
fmt.Println("event fired.")
return nil
})
return config
}).Init(func(config *DynamicConfig) {
cfg = config
})
c.Object(wrapper).Init(func(p *DynamicConfigWrapper) {
p.Wrapper.Slice.Init(make([]string, 0))
p.Wrapper.Map.Init(make(map[string]string))
p.Wrapper.Event.OnEvent(func(prop *conf.Properties) error {
fmt.Println("event fired.")
return nil
})
})
err := c.Refresh()
assert.Nil(t, err)
{
b, _ := json.Marshal(cfg)
assert.Equal(t, string(b), `{"Int":3,"Float":1.2,"Map":{},"Slice":[],"Event":{}}`)
b, _ = json.Marshal(wrapper)
assert.Equal(t, string(b), `{"Wrapper":{"Int":3,"Float":1.2,"Map":{},"Slice":[],"Event":{}}}`)
}
{
p := conf.New()
p.Set("int", 4)
p.Set("float", 2.3)
p.Set("map.a", 1)
p.Set("map.b", 2)
p.Set("slice[0]", 3)
p.Set("slice[1]", 4)
p.Set("wrapper.int", 3)
p.Set("wrapper.float", 1.5)
p.Set("wrapper.map.a", 9)
p.Set("wrapper.map.b", 8)
p.Set("wrapper.slice[0]", 4)
p.Set("wrapper.slice[1]", 6)
c.Properties().Refresh(p)
}
{
b, _ := json.Marshal(cfg)
assert.Equal(t, string(b), `{"Int":4,"Float":2.3,"Map":{"a":"1","b":"2"},"Slice":["3","4"],"Event":{}}`)
b, _ = json.Marshal(wrapper)
assert.Equal(t, string(b), `{"Wrapper":{"Int":3,"Float":1.5,"Map":{"a":"9","b":"8"},"Slice":["4","6"],"Event":{}}}`)
}
}
Bean sharing
Java Spring Redis uses a very special feature on the front page, which can inject the field value of one bean into another object, which looks like the bean is shared. Now Go-Spring can also support such usage.
type runner struct {
Client *redis.Client `autowire:""`
StrOps *redis.StringOperations `autowire:"RedisClient"`
}
func (r *runner) Run(ctx gs.Context) {
_, err := r.Client.OpsForString().Get(ctx.Context(), "nonexisting")
if !redis.IsErrNil(err) {
panic(errors.New("should be redis.ErrNil"))
}
_, err = r.Client.OpsForString().Set(ctx.Context(), "mykey", "Hello")
util.Panic(err).When(err != nil)
v, err := r.Client.OpsForString().Get(ctx.Context(), "mykey")
util.Panic(err).When(err != nil)
if v != "Hello" {
panic(errors.New("should be \"Hello\""))
}
v, err = r.StrOps.Get(ctx.Context(), "mykey")
util.Panic(err).When(err != nil)
if v != "Hello" {
panic(errors.New("should be \"Hello\""))
}
go gs.ShutDown()
}
func main() {
gs.Object(&runner{}).Export((*gs.AppRunner)(nil))
fmt.Printf("program exited %v\n", gs.Web(false).Run())
}
#Onestop #development #framework #GoSpring #released #v112 #version #News Fast Delivery