Skip to content

Commit 259c5e4

Browse files
committed
Update test cases and simplify container logic
1 parent 8ba7d4b commit 259c5e4

File tree

5 files changed

+259
-278
lines changed

5 files changed

+259
-278
lines changed

gs/app.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,17 @@ type AppEvent interface {
3939

4040
// App Ioc App
4141
type App struct {
42+
props *conf.Properties
4243
container *container
4344
exitChan chan struct{}
4445
}
4546

4647
// NewApp make a new App
4748
func NewApp() *App {
49+
props := conf.New()
4850
return &App{
49-
container: New().(*container),
51+
props: props,
52+
container: NewContainer(props).(*container),
5053
exitChan: make(chan struct{}),
5154
}
5255
}
@@ -63,26 +66,23 @@ func (app *App) Run(resourceLocator ...ResourceLocator) error {
6366

6467
func (app *App) run(resourceLocator ResourceLocator) error {
6568

66-
e := NewAppConfiguration(resourceLocator)
67-
68-
if err := e.Load(app.container.props); nil != err {
69+
// load resource configuration.
70+
if err := NewAppConfiguration(resourceLocator).Load(app.props); nil != err {
6971
return err
7072
}
7173

72-
if showBanner, _ := strconv.ParseBool(app.container.props.Get("spring.config.banner", conf.Def("true"))); showBanner {
73-
app.printBanner(app.getBanner(app.container.props))
74-
}
74+
// print spring banner in console.
75+
app.printBanner(app.props)
7576

76-
if err := app.container.p.Refresh(app.container.props); nil != err {
77-
return err
78-
}
79-
80-
if err := app.container.refresh(true); err != nil {
77+
// Refresh the container's beans.
78+
if err := app.container.Refresh(); err != nil {
79+
app.container.Close()
8180
return err
8281
}
8382

8483
var logger = GetLogger()
8584

85+
// post OnAppStart event.
8686
app.onAppStart(app.container)
8787

8888
logger.Info("application started successfully")
@@ -92,13 +92,15 @@ func (app *App) run(resourceLocator ResourceLocator) error {
9292
ch := make(chan os.Signal, 1)
9393
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
9494
sig := <-ch
95-
app.Shutdown(fmt.Sprintf("signal %v", sig))
95+
app.Shutdown("received signal: " + sig.String())
9696
}()
9797

9898
<-app.exitChan
9999

100+
// post OnAppStop event.
100101
app.onAppStop(app.container)
101102

103+
// close container.
102104
app.container.Close()
103105

104106
logger.Info("application exited")
@@ -158,8 +160,12 @@ func (app *App) getBanner(p *conf.Properties) string {
158160
}
159161

160162
// printBanner print banner to console.
161-
func (app *App) printBanner(banner string) {
162-
fmt.Println(banner)
163+
func (app *App) printBanner(p *conf.Properties) {
164+
if showBanner, _ := strconv.ParseBool(p.Get("spring.config.banner", conf.Def("true"))); showBanner {
165+
if banner := app.getBanner(p); len(banner) > 0 {
166+
fmt.Println(banner)
167+
}
168+
}
163169
}
164170

165171
// Shutdown close application.
@@ -180,8 +186,8 @@ func (app *App) OnProperty(key string, fn interface{}) {
180186
}
181187

182188
// Property set property key/value
183-
func (app *App) Property(key string, value interface{}) {
184-
app.container.Property(key, value)
189+
func (app *App) Property(key string, value interface{}) error {
190+
return app.container.Property(key, value)
185191
}
186192

187193
// Accept register bean to Ioc container.

gs/app_configuration.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ func (e *AppConfiguration) Load(props *conf.Properties) error {
5757

5858
// 从环境变量和参数获取的配置优先级更高
5959
for _, k := range p.Keys() {
60-
props.Set(k, p.Get(k))
60+
if err := props.Set(k, p.Get(k)); nil != err {
61+
return err
62+
}
6163
}
6264
return nil
6365
}

gs/gs.go

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,28 @@ var (
5454

5555
type BeanSelector = utils.BeanSelector
5656

57+
// Container provides interfaces for registering properties and beans before the IoC container starts up.
5758
type Container interface {
59+
// Context return context of IoC container.
5860
Context() context.Context
61+
// OnProperty binding a callback when the property key loaded.
62+
OnProperty(key string, fn interface{}) error
63+
// Property sets the value of the property corresponding to the key. If the property value for the key already exists, the Set method will overwrite the old value.
64+
// In addition to supporting string type property values, the Set method also supports other primitive data types such as int, uint, bool, and so on for property values.
65+
Property(key string, value interface{}) error
66+
// Properties return properties of IoC container.
5967
Properties() *dync.Properties
68+
// AllowCircularReferences enable circular-references.
6069
AllowCircularReferences()
70+
// Object register object bean to Ioc container.
6171
Object(i interface{}) *BeanDefinition
72+
// Provide register method bean to Ioc container.
6273
Provide(ctor interface{}, args ...arg.Arg) *BeanDefinition
74+
// Configuration scan that the object `i` has `NewXXX` methods to Ioc container.
6375
Configuration(i interface{}) *BeanDefinition
76+
// Refresh the container's beans, perform validity checks on beans, and complete property binding and dependency injection.
6477
Refresh() error
78+
// Close clos Ioc container.
6579
Close()
6680
}
6781

@@ -100,6 +114,8 @@ type tempContainer struct {
100114
mapOfOnProperty map[string]interface{}
101115
}
102116

117+
var _ Context = (*container)(nil)
118+
103119
// The container is the cornerstone of the go-spring framework, implementing the concept of dependency injection mentioned in
104120
// Martin Fowler's article "Inversion of Control Containers and the Dependency Injection pattern."
105121
// However, the original article only refers to dependency injection as the handling of dependencies between objects,
@@ -118,20 +134,25 @@ type container struct {
118134
dependencies []*BeanDefinition
119135
state refreshState
120136
wg sync.WaitGroup
121-
p *dync.Properties
137+
properties *dync.Properties
122138
contextAware bool
123139
allowCircularReferences bool
124140
}
125141

126142
// New make a IoC container.
127143
func New() Container {
144+
return NewContainer(conf.New())
145+
}
146+
147+
// NewContainer make a IoC container with Properties.
148+
func NewContainer(props *conf.Properties) Container {
128149
ctx, cancel := context.WithCancel(context.Background())
129150
return &container{
130-
ctx: ctx,
131-
cancel: cancel,
132-
p: dync.New(),
151+
ctx: ctx,
152+
cancel: cancel,
153+
properties: dync.New(),
133154
tempContainer: &tempContainer{
134-
props: conf.New(),
155+
props: props,
135156
beansByName: make(map[string][]*BeanDefinition),
136157
beansByType: make(map[reflect.Type][]*BeanDefinition),
137158
mapOfOnProperty: make(map[string]interface{}),
@@ -146,7 +167,7 @@ func (c *container) Context() context.Context {
146167

147168
// Properties return properties of IoC container.
148169
func (c *container) Properties() *dync.Properties {
149-
return c.p
170+
return c.properties
150171
}
151172

152173
func validOnProperty(fn interface{}) error {
@@ -161,16 +182,24 @@ func validOnProperty(fn interface{}) error {
161182
}
162183

163184
// OnProperty binding a callback when the property key loaded.
164-
func (c *container) OnProperty(key string, fn interface{}) {
165-
err := validOnProperty(fn)
166-
utils.Panic(err).When(err != nil)
185+
func (c *container) OnProperty(key string, fn interface{}) error {
186+
if c.state >= Refreshing {
187+
return errors.New("should call before Refresh")
188+
}
189+
if err := validOnProperty(fn); nil != err {
190+
return err
191+
}
167192
c.mapOfOnProperty[key] = fn
193+
return nil
168194
}
169195

170196
// Property sets the value of the property corresponding to the key. If the property value for the key already exists, the Set method will overwrite the old value.
171197
// In addition to supporting string type property values, the Set method also supports other primitive data types such as int, uint, bool, and so on for property values.
172-
func (c *container) Property(key string, value interface{}) {
173-
c.props.Set(key, value)
198+
func (c *container) Property(key string, value interface{}) error {
199+
if c.state >= Refreshing {
200+
return errors.New("should call before Refresh")
201+
}
202+
return c.props.Set(key, value)
174203
}
175204

176205
// Accept register bean to Ioc container.
@@ -367,16 +396,16 @@ func (c *container) clear() {
367396
}
368397

369398
// Refresh the container's beans, perform validity checks on beans, and complete property binding and dependency injection.
370-
func (c *container) Refresh() error {
371-
return c.refresh(true)
372-
}
373-
374-
func (c *container) refresh(autoClear bool) (err error) {
399+
func (c *container) Refresh() (err error) {
375400

376401
if c.state != Unrefreshed {
377402
return errors.New("container already refreshed")
378403
}
379404

405+
if err = c.properties.Refresh(c.props); nil != err {
406+
return err
407+
}
408+
380409
start := time.Now()
381410
c.state = RefreshInit
382411

@@ -385,7 +414,7 @@ func (c *container) refresh(autoClear bool) (err error) {
385414
for key, f := range c.mapOfOnProperty {
386415
t := reflect.TypeOf(f)
387416
in := reflect.New(t.In(0)).Elem()
388-
if err = c.p.Bind(in, conf.Key(key)); err != nil {
417+
if err = c.properties.Bind(in, conf.Key(key)); err != nil {
389418
return err
390419
}
391420
reflect.ValueOf(f).Call([]reflect.Value{in})
@@ -458,7 +487,7 @@ func (c *container) refresh(autoClear bool) (err error) {
458487
cost := time.Now().Sub(start)
459488
c.logger.Info(fmt.Sprintf("refresh %d beans cost %v", len(beansById), cost))
460489

461-
if autoClear && !c.contextAware {
490+
if !c.contextAware {
462491
c.clear()
463492
}
464493

@@ -726,7 +755,7 @@ func (a *argContext) Matches(c cond.Condition) (bool, error) {
726755
}
727756

728757
func (a *argContext) Bind(v reflect.Value, tag string) error {
729-
return a.c.p.Bind(v, conf.Tag(tag))
758+
return a.c.properties.Bind(v, conf.Tag(tag))
730759
}
731760

732761
func (a *argContext) Wire(v reflect.Value, tag string) error {
@@ -817,7 +846,7 @@ func (c *container) wireStruct(v reflect.Value, t reflect.Type, param conf.BindP
817846

818847
// tag 预处理,可能通过属性值进行指定。
819848
if strings.HasPrefix(tag, "${") {
820-
s, err := c.p.Resolve(tag)
849+
s, err := c.properties.Resolve(tag)
821850
if nil != err {
822851
return fmt.Errorf("field %s failed resolve logger name: %w", fieldPath, err)
823852
}
@@ -879,7 +908,7 @@ func (c *container) wireStruct(v reflect.Value, t reflect.Type, param conf.BindP
879908
return err
880909
}
881910
} else {
882-
err = c.p.BindValue(fv.Addr(), subParam)
911+
err = c.properties.BindValue(fv.Addr(), subParam)
883912
if err != nil {
884913
return err
885914
}
@@ -901,7 +930,7 @@ func (c *container) wireByTag(v reflect.Value, tag string, stack *wiringStack) e
901930

902931
// tag 预处理,可能通过属性值进行指定。
903932
if strings.HasPrefix(tag, "${") {
904-
s, err := c.p.Resolve(tag)
933+
s, err := c.properties.Resolve(tag)
905934
if err != nil {
906935
return err
907936
}

gs/gs_context.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,23 @@ import (
2727
)
2828

2929
func (c *container) Keys() []string {
30-
return c.p.Keys()
30+
return c.properties.Keys()
3131
}
3232

3333
func (c *container) Has(key string) bool {
34-
return c.p.Has(key)
34+
return c.properties.Has(key)
3535
}
3636

3737
func (c *container) Prop(key string, opts ...conf.GetOption) string {
38-
return c.p.Get(key, opts...)
38+
return c.properties.Get(key, opts...)
3939
}
4040

4141
func (c *container) Resolve(s string) (string, error) {
42-
return c.p.Resolve(s)
42+
return c.properties.Resolve(s)
4343
}
4444

4545
func (c *container) Bind(i interface{}, args ...conf.BindArg) error {
46-
return c.p.Bind(i, args...)
46+
return c.properties.Bind(i, args...)
4747
}
4848

4949
// Find the bean objects that meet the specified conditions. Note that this function can only guarantee that the returned beans are valid, i.e.,

0 commit comments

Comments
 (0)