Skip to content

Commit f8a2a2b

Browse files
authored
Merge pull request #2 from ComingCL/fix
fix: 注入在对象内部手动创建的需要注入的对象
2 parents c604eb5 + c6b5707 commit f8a2a2b

File tree

3 files changed

+213
-8
lines changed

3 files changed

+213
-8
lines changed

deep_inject_test.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package inject
2+
3+
import "testing"
4+
5+
// 测试深度注入的各种场景
6+
func TestDeepInjectAdvanced(t *testing.T) {
7+
// 场景1: 多层嵌套的手动注入实例
8+
type Level3 struct {
9+
Value string
10+
}
11+
12+
type Level2 struct {
13+
L3 *Level3 `inject:""`
14+
}
15+
16+
type Level1 struct {
17+
L2 *Level2 `inject:""`
18+
}
19+
20+
type Root struct {
21+
L1 *Level1 `inject:""`
22+
}
23+
24+
var g Graph
25+
26+
// 手动创建嵌套结构
27+
root := &Root{
28+
L1: &Level1{
29+
L2: &Level2{
30+
L3: &Level3{Value: "manually created"},
31+
},
32+
},
33+
}
34+
35+
// 提供根对象
36+
if err := g.Provide(&Object{Value: root}); err != nil {
37+
t.Fatal("failed to provide root:", err)
38+
}
39+
40+
// 执行深度注入
41+
if err := g.Populate(); err != nil {
42+
t.Fatal("failed to populate:", err)
43+
}
44+
45+
// 验证深度注入是否成功
46+
if root.L1 == nil {
47+
t.Fatal("root.L1 should not be nil")
48+
}
49+
if root.L1.L2 == nil {
50+
t.Fatal("root.L1.L2 should not be nil")
51+
}
52+
if root.L1.L2.L3 == nil {
53+
t.Fatal("root.L1.L2.L3 should not be nil")
54+
}
55+
if root.L1.L2.L3.Value != "manually created" {
56+
t.Fatal("deep injected value should be preserved")
57+
}
58+
}
59+
60+
func TestDeepInjectWithMixedProvision(t *testing.T) {
61+
// 场景2: 混合手动创建和依赖注入提供的实例
62+
type ServiceA struct {
63+
Name string
64+
}
65+
66+
type ServiceB struct {
67+
A *ServiceA `inject:""`
68+
}
69+
70+
type ServiceC struct {
71+
B *ServiceB `inject:""`
72+
}
73+
74+
var g Graph
75+
76+
// 手动提供ServiceA
77+
serviceA := &ServiceA{Name: "ServiceA"}
78+
if err := g.Provide(&Object{Value: serviceA}); err != nil {
79+
t.Fatal("failed to provide serviceA:", err)
80+
}
81+
82+
// 手动创建包含部分依赖的ServiceC
83+
serviceC := &ServiceC{
84+
B: &ServiceB{}, // B没有A的依赖
85+
}
86+
87+
if err := g.Provide(&Object{Value: serviceC}); err != nil {
88+
t.Fatal("failed to provide serviceC:", err)
89+
}
90+
91+
// 执行注入
92+
if err := g.Populate(); err != nil {
93+
t.Fatal("failed to populate:", err)
94+
}
95+
96+
// 验证混合注入结果
97+
if serviceC.B == nil {
98+
t.Fatal("serviceC.B should not be nil")
99+
}
100+
if serviceC.B.A == nil {
101+
t.Fatal("serviceC.B.A should be injected")
102+
}
103+
if serviceC.B.A != serviceA {
104+
t.Fatal("serviceC.B.A should be the same instance as serviceA")
105+
}
106+
if serviceC.B.A.Name != "ServiceA" {
107+
t.Fatal("injected service should preserve its properties")
108+
}
109+
}
110+
111+
func TestDeepInjectCircularDependency(t *testing.T) {
112+
// 场景3: 测试循环依赖的处理(这应该能正常工作)
113+
type CircularB struct {
114+
A interface{} `inject:""`
115+
}
116+
117+
type CircularA struct {
118+
B *CircularB `inject:""`
119+
}
120+
121+
var g Graph
122+
123+
// 手动创建一个带有循环依赖的结构
124+
a := &CircularA{}
125+
b := &CircularB{A: a}
126+
a.B = b
127+
128+
// 提供到依赖图
129+
if err := g.Provide(&Object{Value: a}); err != nil {
130+
t.Fatal("failed to provide a:", err)
131+
}
132+
133+
if err := g.Provide(&Object{Value: b}); err != nil {
134+
t.Fatal("failed to provide b:", err)
135+
}
136+
137+
// 执行注入
138+
if err := g.Populate(); err != nil {
139+
t.Fatal("failed to populate:", err)
140+
}
141+
142+
// 验证循环依赖保持完整
143+
if a.B != b {
144+
t.Fatal("circular dependency should be preserved")
145+
}
146+
if b.A.(*CircularA) != a {
147+
t.Fatal("circular dependency should be preserved")
148+
}
149+
}

inject.go

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,56 @@ func (g *Graph) Provide(objects ...*Object) error {
114114
return nil
115115
}
116116

117+
// provideForDeepInject 专门用于深度注入时提供对象,允许同类型的多个实例
118+
func (g *Graph) provideForDeepInject(o *Object) error {
119+
o.reflectType = reflect.TypeOf(o.Value)
120+
o.reflectValue = reflect.ValueOf(o.Value)
121+
122+
if o.Fields != nil {
123+
return fmt.Errorf("fields were specified on object %v when it was provided", o)
124+
}
125+
126+
if o.Name == "" {
127+
if !isStructPtr(o.reflectType) {
128+
return fmt.Errorf(
129+
"expected unnamed object value to be a pointer to a struct but got type %s with value %v",
130+
o.reflectType,
131+
o.Value)
132+
}
133+
134+
// 对于深度注入,我们不检查类型重复,直接添加到unnamed列表
135+
// 但我们需要检查是否已经存在相同的实例(相同的指针)
136+
for _, existing := range g.unnamed {
137+
if existing.Value == o.Value {
138+
// 相同的实例已存在,不需要重复添加
139+
return nil
140+
}
141+
}
142+
143+
g.unnamed = append(g.unnamed, o)
144+
} else {
145+
if g.named == nil {
146+
g.named = make(map[string]*Object)
147+
}
148+
149+
if g.named[o.Name] != nil {
150+
return fmt.Errorf("provided two instances named %s", o.Name)
151+
}
152+
g.named[o.Name] = o
153+
}
154+
155+
if g.Logger != nil {
156+
if o.created {
157+
g.Logger.Info("created %v", o)
158+
} else if o.embedded {
159+
g.Logger.Info("provided embedded %v", o)
160+
} else {
161+
g.Logger.Info("provided %v for deep injection", o)
162+
}
163+
}
164+
return nil
165+
}
166+
117167
// Populate 填充不完整的对象
118168
func (g *Graph) Populate() error {
119169
for _, o := range g.named {
@@ -235,14 +285,16 @@ StructLoop:
235285
private: false,
236286
created: false,
237287
}
238-
if err := g.Provide(existingObject); err == nil {
239-
// 递归填充现有对象的依赖(深度注入)
240-
if err := g.populateExplicit(existingObject); err != nil {
241-
return err
242-
}
243-
if g.Logger != nil {
244-
g.Logger.Info("deep injected existing %v in field %s of %v", existingObject, o.reflectType.Elem().Field(i).Name, o)
245-
}
288+
// 对于深度注入,我们需要特殊处理类型重复的情况
289+
if err := g.provideForDeepInject(existingObject); err != nil {
290+
return fmt.Errorf("failed to provide existing object for deep injection: %v", err)
291+
}
292+
// 递归填充现有对象的依赖(深度注入)
293+
if err := g.populateExplicit(existingObject); err != nil {
294+
return err
295+
}
296+
if g.Logger != nil {
297+
g.Logger.Info("deep injected existing %v in field %s of %v", existingObject, o.reflectType.Elem().Field(i).Name, o)
246298
}
247299
}
248300
}

inject_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,7 @@ type TypeAForTestDeepInject struct {
998998
}
999999

10001000
type TypeBForTestDeepInject struct {
1001+
A *TypeAForTestDeepInject `inject:""`
10011002
}
10021003

10031004
type TypeCForTestDeepInject struct {
@@ -1046,4 +1047,7 @@ func TestForDeepInject(t *testing.T) {
10461047
if d.A.C.B == nil {
10471048
t.Fatal("d.A.C.B is nil")
10481049
}
1050+
if b.A == nil {
1051+
t.Fatal("b.A is nil")
1052+
}
10491053
}

0 commit comments

Comments
 (0)