@@ -54,14 +54,28 @@ var (
5454
5555type BeanSelector = utils.BeanSelector
5656
57+ // Container provides interfaces for registering properties and beans before the IoC container starts up.
5758type 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.
127143func 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.
148169func (c * container ) Properties () * dync.Properties {
149- return c .p
170+ return c .properties
150171}
151172
152173func 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
728757func (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
732761func (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 }
0 commit comments