newposts
This commit is contained in:
26
src/content/posts/Java/Spring/SpringBoot是如何实现自动配置的.md
Normal file
26
src/content/posts/Java/Spring/SpringBoot是如何实现自动配置的.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: SpringBoot是如何实现自动配置的
|
||||
published: 2025-09-15
|
||||
description: ''
|
||||
image: ''
|
||||
tags: ['SpringBoot','Java','自动配置']
|
||||
category: 'Java > Spring'
|
||||
draft: false
|
||||
lang: ''
|
||||
---
|
||||
|
||||
# SpringBoot是如何实现自动配置的
|
||||
|
||||
Spring Boot的自动配置是通过 `@EnableAutoConfiguration` 注解来实现的。
|
||||
这个注解包含 `@Import({AutoConfigurationImportSelector.class})`注解
|
||||
导入的这两个类会扫描classpath下所有的`META-INF/spring.factories`中的文件,根据文件中指定的配置类加载相应的Bean的自动配置。
|
||||
|
||||
这些Bean通常会使用 `@ConditionOnClass`,`@ConditionOnMissingBean`,`@ConditionalOnProperty`等注解来控制自动配置的加载条件,例如仅在类路径中存在某个类的时候,才加载某些配置。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
39
src/content/posts/Java/Spring/什么是循环依赖.md
Normal file
39
src/content/posts/Java/Spring/什么是循环依赖.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: 什么是循环依赖
|
||||
published: 2025-09-16
|
||||
description: ''
|
||||
image: ''
|
||||
tags: [Spring,循环依赖,Java]
|
||||
category: 'Java > Spring'
|
||||
draft: false
|
||||
lang: ''
|
||||
---
|
||||
|
||||
# 什么是循环依赖
|
||||
循环依赖就是指两个或者多个模块,类组件之间互相依赖,形成一个闭环
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class A {
|
||||
@Autowired
|
||||
private B b;
|
||||
}
|
||||
|
||||
@Service
|
||||
public class B {
|
||||
@Autowired
|
||||
private A a;
|
||||
}
|
||||
|
||||
//或者自己依赖自己
|
||||
@Service
|
||||
public class A {
|
||||
@Autowired
|
||||
private A a;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
就像上面这种情况,就属于循环依赖
|
||||
|
||||
|
||||
109
src/content/posts/Java/Spring/如何解决循环依赖.md
Normal file
109
src/content/posts/Java/Spring/如何解决循环依赖.md
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: Spring如何解决循环依赖
|
||||
published: 2025-09-16
|
||||
description: ''
|
||||
image: ''
|
||||
tags: [Spring,循环依赖,Java]
|
||||
category: 'Java > Spring'
|
||||
draft: false
|
||||
lang: ''
|
||||
---
|
||||
|
||||
# Spring如何解决循环依赖
|
||||
|
||||
关键是`提前暴露未完全创建完毕的Bean`
|
||||
Spring中采用了`三级缓存`解决了循环依赖
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
我们拿下面这个例子来讲
|
||||
```java
|
||||
@Service
|
||||
public class A {
|
||||
@Autowired
|
||||
private B b;
|
||||
}
|
||||
|
||||
@Service
|
||||
public class B {
|
||||
@Autowired
|
||||
private A a;
|
||||
}
|
||||
|
||||
//或者自己依赖自己
|
||||
@Service
|
||||
public class A {
|
||||
@Autowired
|
||||
private A a;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
首先要创建Bean A,去一级缓存里面找,发现没有,二级缓存里面找,发现也没有,三级里面也没有
|
||||
这个时候进入Bean A 的对象创建流程
|
||||
|
||||
接下来我们利用反射创建对象A,调用其无参构造方法,创建一个对象A 的实例,并将其包装成ObjectFactory放入三级缓存中。
|
||||

|
||||
|
||||

|
||||
|
||||
接下来要填充属性
|
||||

|
||||
|
||||
因为A对象的属性是B对象
|
||||
|
||||
所以现在要开始创建Bean B
|
||||
到一级,二级,三级缓存中找B对象,发现不存在,所以进入B对象的创建流程
|
||||
|
||||
依然是通过反射,调用B的无参构造方法创建B的实例,并将其包装成ObjectFactory放入三级缓存中。
|
||||

|
||||
|
||||
接下来要填充B对象的属性,就又要进入Bean A的创建流程中,再去缓存中查找A对象,我们能发现在三级缓存中已经有A的ObjectFactory了
|
||||
|
||||

|
||||

|
||||
|
||||
可以从源码中看到,我们会调用存放在三级缓存中A的ObjectFactory的getObject方法,创建单例对象,存放在earlySingletonObjects里面(二级缓存),然后从三级缓存中移除A的ObjectFactory
|
||||
|
||||

|
||||
|
||||
|
||||
好的,这样的话,我们就可以把A填充到B对象需要的属性里面了
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
我们看看缓存转移的关键源码
|
||||

|
||||
第一步先把B的完整对象放到一级缓存中,然后从三级缓存中移除B的ObjectFactory,再从二级缓存中移除B(当然二级缓存中也没有B),接下来完成B的单例注册。这样缓存转移就完成了。
|
||||
|
||||

|
||||
这样就完成了B对象的初始化
|
||||

|
||||
|
||||
但是我们B对象的创建流程是在A对象的填充属性流程里,所以会继续A的填充属性流程,这个时候再去一级缓存里找B,就能找到B了,填充B并进行缓存转移,移除二级,三级缓存中的A对象,就可以注入B完成A初始化了
|
||||

|
||||
|
||||
|
||||
|
||||
# 三级缓存的作用
|
||||
为了AOP
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
当Spring没有循环依赖的情况下,是把普通对象创建好后再生成代理对象,Spring也没有办法提前知道对象之间的依赖关系。也不能把每个对象都创建出代理对象来,所以就需要把对象包装成objectFactory这个类型,通过其中的ObjectFactory对象中的getObject方法获取到生成的代理对象。
|
||||
|
||||

|
||||
Reference in New Issue
Block a user