0


Spring如何解决循环依赖?

一、Spring容器启动流程

创建配置类

@ComponentScan(value ={"com.woniu"})@ConfigurationpublicclassMyConfig{}

创建一个普通类

packagecom.woniu.service;importorg.springframework.stereotype.Component;@ComponentpublicclassEservice{}

创建一个启动类

publicclassApplication{publicstaticvoidmain(String[] args){AnnotationConfigApplicationContext context =newAnnotationConfigApplicationContext(MyConfig.class);}}

在启动类的第三行打断点开始单步调试,进入spring的容器启动流程

1

2

3

4

5

6

7

8

这个方法非常重要,在循环依赖中对于同一个bean会多次调用,先从一级缓存中查询是否存在bean,若不存在,再从二级缓存中查询是否存在bean,如果还是没有找到,从三级缓存中查询singletonFactory,如果没有,则直接返回,若在三级缓存中找到singletonFactory,则调用工厂中的方法创建bean,然后在把bean添加到二级缓存中

9

什么是三级缓存

10

11

12

13

14.png

15

16

17

18

19.png

20

21.png

22

23

25

26

二、简单依赖注入

再创建一个普通类

packagecom.woniu.service;importorg.springframework.stereotype.Component;@ComponentpublicclassFservice{}

修改一下Eservice,注入Fservice实例

packagecom.woniu.service;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;@ComponentpublicclassEservice{@AutowiredprivateFservice fservice;}

27.png

28.png

29.png

30.png

31.png

32.png

33.png

在这个populateBean里面注入Fservice的实例到Eservice中

35

36

38

39

40

41

42

43

上面截图中的descriptor.resolveCandidate方法继续跟踪会进入到下面截图的方法,注意,这时候,需要从容器中查找Fservice的实例对象了

![44](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c990e38e9cdd4ff98f131f3d8a1132e1~tplv-k3u1fbpfcp-watermark.image

下面就正式进入创建一个Fservice对象的实例,并且添加到spring的容器中,也就是第一部分讲的spring容器启动流程

45

47

48

把创建好的fservice实例返回给刚才正在处理@Autowired的注解的代码

49

50

51

53

52

54

程序继续运行,把eservice也加入到一级缓存

55

56

三、AOP依赖注入

修改MyConfig

packagecom.woniu;importorg.springframework.context.annotation.ComponentScan;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.EnableAspectJAutoProxy;@ComponentScan(value ={"com.woniu"})@EnableAspectJAutoProxy@ConfigurationpublicclassMyConfig{}

创建MyAop类

importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.aspectj.lang.annotation.Pointcut;importorg.springframework.stereotype.Component;@Component@AspectpublicclassMyAop{//用来定义切入点表达式的方法,方法名就是切入点表达式的名称@Pointcut("execution(* com.woniu.service..*.*(..))")publicvoidpt1(){}@Before("pt1()")publicvoidBefore()throwsThrowable{System.out.println("before aop...");}}

Eservice

packagecom.woniu.service;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;@ComponentpublicclassEservice{@AutowiredprivateFservice fservice;}

Fservice

packagecom.woniu.service;importorg.springframework.stereotype.Component;@ComponentpublicclassFservice{publicvoidprint(){System.out.println("fservice");}}

启动类

packagecom.woniu;importcom.woniu.service.*;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;importorg.springframework.context.annotation.EnableAspectJAutoProxy;publicclassApplication{publicstaticvoidmain(String[] args){AnnotationConfigApplicationContext context =newAnnotationConfigApplicationContext(MyConfig.class);}}

58

59.png

60.png

61.png

62.png

63.png

64.png

65.png

66.png

67.png

68.png

69.png

70.png

71.png

72.png

73.png

74.png

75.png

76.png

77.png

78.png

79.png

此时fservice的原生bean已经实例已经创建完成,initializeBean这个方法将会做初始化,在这里,将会给fservice生成一个代理对象

80.png

81.png

这个BeanPostProcessor会为Fservice生成代理对象,并且放置在二级缓存

82.png

earlyProxyReferences可以帮助判断是否已经生成过代理对象,wrapIfNecessary这个方法就是生成代理对象的方法

83.png

84.png

创建代理工厂

85.png

86.png

87.png
88.png
fservice的代理对象已经被创建出来

89.png

90.png

91.png

initializeBean方法调用完毕,Fservicve代理对象创建完毕

92.png

93.png

94.png

95.png

96.png

此时的一级缓存如下

97.png

98.png

99.png

至此Eservice对象的initializeBean方法执行完毕,fservice的代理对象已经被注入到eservice中

100.png

101.png

四、循环依赖

  1. 非单例V.S非单例
  2. 单例构造函数V.S单例构造函数
  3. 单例构造函数V.S单例普通依赖注入
  4. 单例普通依赖注入V.S单例普通依赖注入
  5. AOP单例普通依赖注入V.SAOP单例普通依赖注入****

五、相关代码

相关代码

标签: java spring

本文转载自: https://blog.csdn.net/ahuangqingfeng/article/details/124080082
版权归原作者 皇家大少つ 所有, 如有侵权,请联系我们删除。

“Spring如何解决循环依赖?”的评论:

还没有评论