Skip to content

Commit a2d4fb4

Browse files
committed
支持延迟注入,解决部分场景下构造函数循环依赖的问题
1 parent 23ce23b commit a2d4fb4

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed

bug_20210329_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package SpringCore_test
18+
19+
import (
20+
"testing"
21+
22+
"github.com/go-spring/spring-core"
23+
)
24+
25+
type circularA struct {
26+
b *circularB
27+
}
28+
29+
func newCircularA(b *circularB) *circularA {
30+
return &circularA{b: b}
31+
}
32+
33+
type circularB struct {
34+
A *circularA `autowire:",lazy"`
35+
}
36+
37+
func newCircularB() *circularB {
38+
return new(circularB)
39+
}
40+
41+
func Test20210329(t *testing.T) {
42+
for i := 0; i < 20; i++ {
43+
ctx := SpringCore.NewDefaultSpringContext()
44+
ctx.RegisterNameBeanFn("1", newCircularA)
45+
ctx.RegisterNameBeanFn("2", newCircularB)
46+
ctx.AutoWireBeans()
47+
}
48+
}

spring-bean-assembly.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,19 @@ func (s *wiringStack) path() (path string) {
7272
return path[:len(path)-1]
7373
}
7474

75+
type lazyField struct {
76+
parent reflect.Value
77+
field string
78+
v reflect.Value
79+
tag string
80+
}
81+
7582
// defaultBeanAssembly beanAssembly 的默认实现
7683
type defaultBeanAssembly struct {
7784
springCtx *defaultSpringContext
7885
wiringStack wiringStack
7986
destroys *list.List // 具有销毁函数的 Bean 的堆栈
87+
lazyFields []lazyField
8088
}
8189

8290
// newDefaultBeanAssembly defaultBeanAssembly 的构造函数
@@ -85,6 +93,7 @@ func newDefaultBeanAssembly(springContext *defaultSpringContext) *defaultBeanAss
8593
springCtx: springContext,
8694
wiringStack: newWiringStack(),
8795
destroys: list.New(),
96+
lazyFields: make([]lazyField, 0),
8897
}
8998
}
9099

@@ -448,6 +457,15 @@ func (assembly *defaultBeanAssembly) wireBeanDefinition(bd beanDefinition, onlyA
448457
assembly.wiringStack.popBack()
449458
}
450459

460+
func lookup(tag reflect.StructTag, keys ...string) (value string, ok bool) {
461+
for _, key := range keys {
462+
if value, ok = tag.Lookup(key); ok {
463+
return
464+
}
465+
}
466+
return
467+
}
468+
451469
// wireObjectBean 对原始对象进行注入
452470
func (assembly *defaultBeanAssembly) wireObjectBean(bd beanDefinition, onlyAutoWire bool) {
453471
st := bd.Type()
@@ -502,14 +520,13 @@ func (assembly *defaultBeanAssembly) wireObjectBean(bd beanDefinition, onlyAutoW
502520
}
503521
}
504522

505-
// 处理 autowire 标签,autowire 与 inject 等价
506-
if beanId, ok := ft.Tag.Lookup("autowire"); ok {
507-
assembly.wireStructField(fv, beanId, sv, fieldName)
508-
}
509-
510-
// 处理 inject 标签,inject 与 autowire 等价
511-
if beanId, ok := ft.Tag.Lookup("inject"); ok {
512-
assembly.wireStructField(fv, beanId, sv, fieldName)
523+
if beanId, ok := lookup(ft.Tag, "autowire", "inject"); ok {
524+
if strings.HasSuffix(beanId, ",lazy") {
525+
f := lazyField{parent: sv, field: fieldName, v: fv, tag: beanId}
526+
assembly.lazyFields = append(assembly.lazyFields, f)
527+
} else {
528+
assembly.wireStructField(fv, beanId, sv, fieldName)
529+
}
513530
}
514531

515532
// 只处理结构体类型的字段,防止递归所以不支持指针结构体字段
@@ -580,6 +597,9 @@ func (assembly *defaultBeanAssembly) wireFunctionBean(fnValue reflect.Value, fnB
580597
panic(fmt.Errorf("function bean: \"%s\" return nil", bd.FileLine()))
581598
}
582599

600+
// 把 Bean 的原始内容解出来,调试的时候更方便
601+
fnBean.rBean = fnBean.rValue.Interface()
602+
583603
// 对函数的返回值进行自动注入
584604
b := &BeanDefinition{
585605
name: bd.Name(),

spring-bean.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ type springBean interface {
234234

235235
// objectBean 以对象形式注册的 Bean
236236
type objectBean struct {
237+
rBean interface{}
237238
rType reflect.Type // 类型
238239
rValue reflect.Value // 值
239240
typeName string // 原始类型的全限定名
@@ -243,6 +244,7 @@ type objectBean struct {
243244
func newObjectBean(v reflect.Value) *objectBean {
244245
if t := v.Type(); IsRefType(t.Kind()) {
245246
return &objectBean{
247+
rBean: v.Interface(),
246248
rType: t,
247249
rValue: v,
248250
typeName: TypeName(t),

spring-context-default.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,12 @@ func (ctx *defaultSpringContext) AutoWireBeans() {
633633
ctx.runConfigers(assembly)
634634
ctx.wireBeans(assembly)
635635

636+
// 处理被标记为延迟注入的那些 Bean 字段
637+
for _, f := range assembly.lazyFields {
638+
tag := strings.TrimSuffix(f.tag, ",lazy")
639+
assembly.getBeanValue(f.v, ParseSingletonTag(tag), f.parent, f.field)
640+
}
641+
636642
ctx.sortDestroyers()
637643
}
638644

0 commit comments

Comments
 (0)