Spring解決循環(huán)依賴的方法及三級緩存機(jī)制實(shí)踐案例
Spring如何解決循環(huán)依賴:深入理解三級緩存機(jī)制
引言
在我們之前的文章中,我們探討了什么是循環(huán)依賴以及它帶來的問題。作為Java生態(tài)系統(tǒng)中最重要的框架之一,Spring Framework在處理循環(huán)依賴方面有著獨(dú)特而精妙的解決方案。今天,讓我們深入了解Spring是如何通過三級緩存機(jī)制巧妙地解決循環(huán)依賴問題的。
Spring中的循環(huán)依賴場景
典型的循環(huán)依賴示例
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
public void doSomething() {
System.out.println("ServiceA doing something");
serviceB.doSomething();
}
}
@Component
public class ServiceB {
@Autowired
private ServiceC serviceC;
public void doSomething() {
System.out.println("ServiceB doing something");
serviceC.doSomething();
}
}
@Component
public class ServiceC {
@Autowired
private ServiceA serviceA; // 形成循環(huán)依賴:A -> B -> C -> A
public void doSomething() {
System.out.println("ServiceC doing something");
serviceA.doSomething();
}
}構(gòu)造器循環(huán)依賴(Spring無法解決)
@Component
public class ServiceA {
private final ServiceB serviceB;
// 構(gòu)造器注入形成的循環(huán)依賴,Spring無法解決
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}Spring Bean的生命周期
要理解Spring如何解決循環(huán)依賴,首先需要了解Bean的創(chuàng)建過程:
public class SpringBeanLifecycle {
/**
* Spring Bean的完整生命周期
*/
public Object createBean(String beanName, BeanDefinition beanDefinition) {
// 1. 實(shí)例化 - 創(chuàng)建對象實(shí)例(調(diào)用構(gòu)造器)
Object bean = instantiateBean(beanName, beanDefinition);
// 2. 屬性填充 - 依賴注入
populateBean(bean, beanName, beanDefinition);
// 3. 初始化 - 調(diào)用初始化方法
initializeBean(bean, beanName);
return bean;
}
private Object instantiateBean(String beanName, BeanDefinition bd) {
// 通過反射創(chuàng)建實(shí)例
Constructor<?> constructor = bd.getBeanClass().getDeclaredConstructor();
return constructor.newInstance();
}
private void populateBean(Object bean, String beanName, BeanDefinition bd) {
// 處理@Autowired、@Resource等注解
// 這里會觸發(fā)依賴Bean的創(chuàng)建
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
Object dependency = getBean(field.getType());
field.setAccessible(true);
field.set(bean, dependency);
}
}
}
private void initializeBean(Object bean, String beanName) {
// 調(diào)用初始化回調(diào)方法
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
}
}Spring的三級緩存機(jī)制
Spring通過三級緩存來解決單例Bean的循環(huán)依賴問題:
public class DefaultSingletonBeanRegistry {
/** 一級緩存:完成初始化的單例Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二級緩存:完成實(shí)例化但未完成初始化的Bean */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** 三級緩存:單例Bean的工廠 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 正在創(chuàng)建的Bean名稱集合 */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/**
* 獲取單例Bean的核心方法
*/
protected Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 從一級緩存中獲取完全初始化的Bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 從二級緩存中獲取早期Bean引用
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 從三級緩存中獲取Bean工廠
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 調(diào)用工廠方法創(chuàng)建早期Bean引用
singletonObject = singletonFactory.getObject();
// 將早期Bean引用放入二級緩存
this.earlySingletonObjects.put(beanName, singletonObject);
// 從三級緩存中移除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
/**
* 添加單例Bean工廠到三級緩存
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
}
/**
* 將完全初始化的Bean添加到一級緩存
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
}
}
}循環(huán)依賴解決過程詳解
讓我們通過一個具體的例子來看看Spring是如何解決循環(huán)依賴的:
/**
* 模擬Spring解決循環(huán)依賴的完整過程
*/
public class CircularDependencyResolver {
// 三級緩存
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
private Map<String, Object> earlySingletonObjects = new HashMap<>();
private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
private Set<String> singletonsCurrentlyInCreation = new HashSet<>();
/**
* 創(chuàng)建Bean的主要方法
*/
public Object getBean(String beanName) {
// 先嘗試從緩存中獲取
Object singleton = getSingleton(beanName);
if (singleton != null) {
return singleton;
}
// 緩存中沒有,開始創(chuàng)建
return createBean(beanName);
}
private Object createBean(String beanName) {
// 標(biāo)記Bean正在創(chuàng)建中
singletonsCurrentlyInCreation.add(beanName);
try {
// 1. 實(shí)例化Bean
Object bean = instantiateBean(beanName);
// 2. 將Bean工廠放入三級緩存(關(guān)鍵步驟)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, bean));
// 3. 屬性填充(可能觸發(fā)循環(huán)依賴)
populateBean(bean, beanName);
// 4. 初始化Bean
initializeBean(bean, beanName);
// 5. 將完成的Bean放入一級緩存
addSingleton(beanName, bean);
return bean;
} finally {
// 移除創(chuàng)建中標(biāo)記
singletonsCurrentlyInCreation.remove(beanName);
}
}
private Object instantiateBean(String beanName) {
// 模擬通過反射創(chuàng)建Bean實(shí)例
System.out.println("實(shí)例化Bean: " + beanName);
if ("serviceA".equals(beanName)) {
return new ServiceA();
} else if ("serviceB".equals(beanName)) {
return new ServiceB();
}
throw new RuntimeException("Unknown bean: " + beanName);
}
private void populateBean(Object bean, String beanName) {
System.out.println("填充Bean屬性: " + beanName);
// 模擬依賴注入
if (bean instanceof ServiceA) {
ServiceA serviceA = (ServiceA) bean;
// 注入ServiceB,這里會觸發(fā)ServiceB的創(chuàng)建
Object serviceB = getBean("serviceB");
serviceA.setServiceB((ServiceB) serviceB);
} else if (bean instanceof ServiceB) {
ServiceB serviceB = (ServiceB) bean;
// 注入ServiceA,這里會從緩存中獲取早期引用
Object serviceA = getBean("serviceA");
serviceB.setServiceA((ServiceA) serviceA);
}
}
private void initializeBean(Object bean, String beanName) {
System.out.println("初始化Bean: " + beanName);
// 執(zhí)行初始化邏輯
}
/**
* 獲取早期Bean引用(處理AOP代理)
*/
private Object getEarlyBeanReference(String beanName, Object bean) {
System.out.println("獲取早期Bean引用: " + beanName);
// 如果需要AOP代理,在這里創(chuàng)建代理對象
if (needsProxy(beanName)) {
return createProxy(bean);
}
return bean;
}
private boolean needsProxy(String beanName) {
// 簡化的代理判斷邏輯
return beanName.contains("service");
}
private Object createProxy(Object target) {
// 簡化的代理創(chuàng)建邏輯
System.out.println("創(chuàng)建代理對象: " + target.getClass().getSimpleName());
return target; // 實(shí)際應(yīng)該返回代理對象
}
// 其他輔助方法...
private Object getSingleton(String beanName) {
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject == null && singletonsCurrentlyInCreation.contains(beanName)) {
singletonObject = earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
private void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
if (!singletonObjects.containsKey(beanName)) {
singletonFactories.put(beanName, singletonFactory);
earlySingletonObjects.remove(beanName);
}
}
private void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
earlySingletonObjects.remove(beanName);
}
}循環(huán)依賴解決的時序圖
ServiceA創(chuàng)建過程: 1. 實(shí)例化ServiceA 2. 將ServiceA工廠放入三級緩存 3. 填充ServiceA屬性,需要ServiceB | ├─ ServiceB創(chuàng)建過程: │ 1. 實(shí)例化ServiceB │ 2. 將ServiceB工廠放入三級緩存 │ 3. 填充ServiceB屬性,需要ServiceA │ 4. 從三級緩存獲取ServiceA早期引用 │ 5. 完成ServiceB初始化,放入一級緩存 │ 4. 獲得ServiceB實(shí)例,完成ServiceA屬性填充 5. 完成ServiceA初始化,放入一級緩存
為什么需要三級緩存?
只有一級緩存的問題
public class SingleCacheExample {
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
public Object getBean(String beanName) {
Object bean = singletonObjects.get(beanName);
if (bean != null) {
return bean;
}
// 創(chuàng)建Bean
bean = createBean(beanName);
singletonObjects.put(beanName, bean);
return bean;
}
// 問題:在Bean完全創(chuàng)建完成之前,其他Bean無法獲取到它的引用
// 導(dǎo)致循環(huán)依賴無法解決
}只有二級緩存的問題
public class TwoCacheExample {
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
private Map<String, Object> earlySingletonObjects = new HashMap<>();
// 問題:無法處理AOP代理的情況
// 如果Bean需要被代理,早期引用和最終對象可能不是同一個實(shí)例
}三級緩存的優(yōu)勢
/**
* 三級緩存解決的問題:
* 1. 一級緩存:存儲完全初始化的Bean
* 2. 二級緩存:存儲早期Bean引用,解決循環(huán)依賴
* 3. 三級緩存:存儲Bean工廠,延遲決定是否需要代理
*/
public class ThreeCacheAdvantages {
/**
* 三級緩存的關(guān)鍵作用:
* 1. 延遲代理對象的創(chuàng)建
* 2. 確保循環(huán)依賴中代理對象的一致性
* 3. 避免不必要的代理對象創(chuàng)建
*/
private Object getEarlyBeanReference(String beanName, Object bean) {
// 只有在真正需要早期引用時才決定是否創(chuàng)建代理
if (hasCircularDependency(beanName)) {
if (needsProxy(beanName)) {
return createProxy(bean);
}
}
return bean;
}
}AOP與循環(huán)依賴
Spring AOP為循環(huán)依賴的解決增加了復(fù)雜性:
@Component
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional // 這個注解會導(dǎo)致創(chuàng)建AOP代理
public void createUser(User user) {
// 業(yè)務(wù)邏輯
orderService.createDefaultOrder(user);
}
}
@Component
@Service
public class OrderService {
@Autowired
private UserService userService;
@Transactional
public void createDefaultOrder(User user) {
// 業(yè)務(wù)邏輯
userService.validateUser(user);
}
}AOP代理處理過程:
public class AopCircularDependencyHandler {
/**
* 處理AOP代理的循環(huán)依賴
*/
public Object resolveAopCircularDependency(String beanName, Object bean) {
// 1. 檢查是否需要創(chuàng)建代理
if (shouldCreateProxy(bean)) {
// 2. 創(chuàng)建代理對象
Object proxy = createAopProxy(bean);
// 3. 確保早期引用和最終對象的一致性
ensureProxyConsistency(beanName, bean, proxy);
return proxy;
}
return bean;
}
private boolean shouldCreateProxy(Object bean) {
// 檢查是否有@Transactional、@Async等注解
Class<?> beanClass = bean.getClass();
// 檢查類級別注解
if (beanClass.isAnnotationPresent(Transactional.class) ||
beanClass.isAnnotationPresent(Async.class)) {
return true;
}
// 檢查方法級別注解
Method[] methods = beanClass.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Transactional.class) ||
method.isAnnotationPresent(Async.class)) {
return true;
}
}
return false;
}
private Object createAopProxy(Object target) {
// 使用CGLIB或JDK動態(tài)代理創(chuàng)建代理對象
ProxyFactory proxyFactory = new ProxyFactory(target);
// 添加事務(wù)攔截器
proxyFactory.addAdvice(new TransactionInterceptor());
return proxyFactory.getProxy();
}
}Spring無法解決的循環(huán)依賴場景
1. 構(gòu)造器循環(huán)依賴
@Component
public class ServiceA {
private final ServiceB serviceB;
// Spring無法解決構(gòu)造器循環(huán)依賴
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
// 啟動時會拋出異常:
// BeanCurrentlyInCreationException: Error creating bean with name 'serviceA':
// Requested bean is currently in creation: Is there an unresolvable circular reference?2. prototype作用域的循環(huán)依賴
@Component
@Scope("prototype")
public class PrototypeServiceA {
@Autowired
private PrototypeServiceB serviceB;
}
@Component
@Scope("prototype")
public class PrototypeServiceB {
@Autowired
private PrototypeServiceA serviceA;
}
// prototype作用域的Bean每次都會創(chuàng)建新實(shí)例,無法使用緩存解決循環(huán)依賴3. @Async注解的特殊情況
@Component
public class AsyncServiceA {
@Autowired
private AsyncServiceB serviceB;
@Async
public void doAsync() {
serviceB.doSomething();
}
}
@Component
public class AsyncServiceB {
@Autowired
private AsyncServiceA serviceA;
public void doSomething() {
serviceA.doAsync();
}
}
// 在某些情況下,@Async可能導(dǎo)致循環(huán)依賴解決失敗循環(huán)依賴的解決方案
1. 使用@Lazy注解
@Component
public class ServiceA {
private final ServiceB serviceB;
// 使用@Lazy延遲注入,打破循環(huán)依賴
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}2. 使用Setter注入替代構(gòu)造器注入
@Component
public class ServiceA {
private ServiceB serviceB;
// 使用Setter注入替代構(gòu)造器注入
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private ServiceA serviceA;
@Autowired
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
}3. 使用@PostConstruct
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
private ServiceA selfReference;
@PostConstruct
public void init() {
// 在初始化階段設(shè)置自引用
this.selfReference = this;
}
}4. 重新設(shè)計架構(gòu)
// 原始設(shè)計:循環(huán)依賴
@Component
public class UserService {
@Autowired
private OrderService orderService;
public void processUser(User user) {
orderService.processOrder(user.getOrders());
}
}
@Component
public class OrderService {
@Autowired
private UserService userService;
public void processOrder(List<Order> orders) {
for (Order order : orders) {
userService.validateUser(order.getUser());
}
}
}
// 重構(gòu)后:提取公共服務(wù)
@Component
public class ValidationService {
public void validateUser(User user) {
// 用戶驗(yàn)證邏輯
}
public void validateOrder(Order order) {
// 訂單驗(yàn)證邏輯
}
}
@Component
public class UserService {
@Autowired
private ValidationService validationService;
public void processUser(User user) {
validationService.validateUser(user);
// 處理用戶邏輯
}
}
@Component
public class OrderService {
@Autowired
private ValidationService validationService;
public void processOrder(Order order) {
validationService.validateOrder(order);
// 處理訂單邏輯
}
}循環(huán)依賴檢測和調(diào)試
1. 啟用循環(huán)依賴檢測
@Configuration
@EnableAutoConfiguration
public class AppConfig {
@Bean
public static BeanFactoryPostProcessor circularDependencyDetector() {
return new BeanFactoryPostProcessor() {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
if (beanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) beanFactory;
factory.setAllowCircularReferences(false); // 禁用循環(huán)依賴
}
}
};
}
}2. 自定義循環(huán)依賴檢測器
@Component
public class CircularDependencyDetector implements BeanPostProcessor {
private final Set<String> beansInCreation = new HashSet<>();
private final Map<String, Set<String>> dependencyGraph = new HashMap<>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
detectCircularDependency(beanName);
return bean;
}
private void detectCircularDependency(String beanName) {
if (beansInCreation.contains(beanName)) {
throw new BeanCurrentlyInCreationException(
"Circular dependency detected: " + beanName);
}
beansInCreation.add(beanName);
// 分析依賴關(guān)系
analyzeDependencies(beanName);
beansInCreation.remove(beanName);
}
private void analyzeDependencies(String beanName) {
// 通過反射分析Bean的依賴關(guān)系
// 構(gòu)建依賴圖,檢測環(huán)路
}
}3. 循環(huán)依賴調(diào)試工具
@Component
public class CircularDependencyDebugger {
private static final Logger logger = LoggerFactory.getLogger(CircularDependencyDebugger.class);
@EventListener
public void handleContextRefreshed(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
// 分析所有Bean的依賴關(guān)系
analyzeBeanDependencies(context);
}
private void analyzeBeanDependencies(ApplicationContext context) {
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
try {
BeanDefinition beanDefinition =
((ConfigurableApplicationContext) context)
.getBeanFactory()
.getBeanDefinition(beanName);
// 分析依賴關(guān)系
Set<String> dependencies = extractDependencies(beanDefinition);
logger.info("Bean {} depends on: {}", beanName, dependencies);
} catch (Exception e) {
logger.warn("Failed to analyze dependencies for bean: {}", beanName, e);
}
}
}
private Set<String> extractDependencies(BeanDefinition beanDefinition) {
Set<String> dependencies = new HashSet<>();
// 提取構(gòu)造器依賴
ConstructorArgumentValues constructorArgs = beanDefinition.getConstructorArgumentValues();
for (ConstructorArgumentValues.ValueHolder valueHolder : constructorArgs.getGenericArgumentValues()) {
if (valueHolder.getValue() instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) valueHolder.getValue();
dependencies.add(ref.getBeanName());
}
}
// 提取屬性依賴
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue pv : propertyValues.getPropertyValues()) {
if (pv.getValue() instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) pv.getValue();
dependencies.add(ref.getBeanName());
}
}
return dependencies;
}
}性能考慮
1. 三級緩存的性能影響
public class CachePerformanceAnalysis {
/**
* 分析三級緩存對性能的影響
*/
public void analyzePerformance() {
// 1. 內(nèi)存開銷:三個Map需要額外的內(nèi)存
// 2. 查找開銷:需要依次查找三個緩存
// 3. 同步開銷:緩存操作需要同步
long startTime = System.nanoTime();
// 模擬緩存查找
Object bean = getSingletonFromCache("testBean");
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("緩存查找耗時: " + duration + " 納秒");
}
private Object getSingletonFromCache(String beanName) {
// 三級緩存查找的性能開銷
Object singleton = singletonObjects.get(beanName);
if (singleton == null) {
singleton = earlySingletonObjects.get(beanName);
if (singleton == null) {
ObjectFactory<?> factory = singletonFactories.get(beanName);
if (factory != null) {
singleton = factory.getObject();
}
}
}
return singleton;
}
}2. 優(yōu)化建議
@Configuration
public class CircularDependencyOptimization {
/**
* 優(yōu)化循環(huán)依賴處理的配置
*/
@Bean
public static BeanFactoryPostProcessor optimizeCircularDependency() {
return beanFactory -> {
if (beanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) beanFactory;
// 1. 預(yù)分析Bean依賴關(guān)系,提前發(fā)現(xiàn)循環(huán)依賴
preAnalyzeDependencies(factory);
// 2. 優(yōu)化緩存大小
optimizeCacheSize(factory);
// 3. 啟用并發(fā)優(yōu)化
enableConcurrentOptimization(factory);
}
};
}
```java
private static void preAnalyzeDependencies(DefaultListableBeanFactory factory) {
String[] beanNames = factory.getBeanDefinitionNames();
Map<String, Set<String>> dependencyGraph = new HashMap<>();
// 構(gòu)建依賴圖
for (String beanName : beanNames) {
BeanDefinition bd = factory.getBeanDefinition(beanName);
Set<String> dependencies = extractBeanDependencies(bd);
dependencyGraph.put(beanName, dependencies);
}
// 檢測循環(huán)依賴
detectCycles(dependencyGraph);
}
private static void detectCycles(Map<String, Set<String>> graph) {
Set<String> visited = new HashSet<>();
Set<String> recursionStack = new HashSet<>();
for (String node : graph.keySet()) {
if (hasCycle(graph, node, visited, recursionStack)) {
System.out.println("檢測到循環(huán)依賴,涉及Bean: " + node);
}
}
}
private static boolean hasCycle(Map<String, Set<String>> graph, String node,
Set<String> visited, Set<String> recursionStack) {
if (recursionStack.contains(node)) {
return true; // 發(fā)現(xiàn)環(huán)路
}
if (visited.contains(node)) {
return false; // 已經(jīng)訪問過,無環(huán)路
}
visited.add(node);
recursionStack.add(node);
Set<String> neighbors = graph.get(node);
if (neighbors != null) {
for (String neighbor : neighbors) {
if (hasCycle(graph, neighbor, visited, recursionStack)) {
return true;
}
}
}
recursionStack.remove(node);
return false;
}
private static void optimizeCacheSize(DefaultListableBeanFactory factory) {
// 根據(jù)Bean數(shù)量優(yōu)化緩存初始容量
int beanCount = factory.getBeanDefinitionCount();
int optimalCacheSize = Math.max(16, beanCount / 4);
// 這里可以通過反射設(shè)置緩存的初始容量
// 實(shí)際實(shí)現(xiàn)中需要訪問私有字段
}
private static void enableConcurrentOptimization(DefaultListableBeanFactory factory) {
// 啟用并發(fā)創(chuàng)建Bean的優(yōu)化
factory.setAllowEagerClassLoading(true);
factory.setAllowRawInjectionDespiteWrapping(true);
}
}實(shí)際應(yīng)用案例
案例1:微服務(wù)中的循環(huán)依賴
/**
* 微服務(wù)架構(gòu)中常見的循環(huán)依賴場景
*/
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Autowired
private NotificationService notificationService;
@Transactional
public User createUser(CreateUserRequest request) {
User user = new User(request);
user = userRepository.save(user);
// 創(chuàng)建用戶后,創(chuàng)建默認(rèn)訂單
orderService.createWelcomeOrder(user);
// 發(fā)送歡迎通知
notificationService.sendWelcomeNotification(user);
return user;
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 循環(huán)依賴
@Autowired
private PaymentService paymentService;
@Transactional
public Order createWelcomeOrder(User user) {
Order order = new Order(user, getWelcomeProducts());
order = orderRepository.save(order);
// 更新用戶的訂單統(tǒng)計
userService.updateOrderStatistics(user.getId());
return order;
}
}
@Service
public class NotificationService {
@Autowired
private UserService userService; // 另一個循環(huán)依賴
public void sendWelcomeNotification(User user) {
// 獲取用戶偏好設(shè)置
UserPreference preference = userService.getUserPreference(user.getId());
if (preference.isEmailEnabled()) {
emailService.sendWelcomeEmail(user);
}
if (preference.isSmsEnabled()) {
smsService.sendWelcomeSms(user);
}
}
}解決方案:
/**
* 重構(gòu)后的解決方案:使用事件驅(qū)動架構(gòu)
*/
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Transactional
public User createUser(CreateUserRequest request) {
User user = new User(request);
user = userRepository.save(user);
// 發(fā)布用戶創(chuàng)建事件,而不是直接調(diào)用其他服務(wù)
eventPublisher.publishEvent(new UserCreatedEvent(user));
return user;
}
public void updateOrderStatistics(Long userId) {
// 更新用戶訂單統(tǒng)計
User user = userRepository.findById(userId);
user.incrementOrderCount();
userRepository.save(user);
}
public UserPreference getUserPreference(Long userId) {
return userPreferenceRepository.findByUserId(userId);
}
}
@Service
public class OrderService {
// 移除對UserService的直接依賴
@EventListener
@Async
public void handleUserCreated(UserCreatedEvent event) {
createWelcomeOrder(event.getUser());
}
@Transactional
public Order createWelcomeOrder(User user) {
Order order = new Order(user, getWelcomeProducts());
order = orderRepository.save(order);
// 發(fā)布訂單創(chuàng)建事件
eventPublisher.publishEvent(new OrderCreatedEvent(order));
return order;
}
}
@Service
public class NotificationService {
// 移除對UserService的直接依賴
@Autowired
private UserPreferenceRepository userPreferenceRepository;
@EventListener
@Async
public void handleUserCreated(UserCreatedEvent event) {
sendWelcomeNotification(event.getUser());
}
public void sendWelcomeNotification(User user) {
// 直接查詢用戶偏好,避免循環(huán)依賴
UserPreference preference = userPreferenceRepository.findByUserId(user.getId());
if (preference.isEmailEnabled()) {
emailService.sendWelcomeEmail(user);
}
if (preference.isSmsEnabled()) {
smsService.sendWelcomeSms(user);
}
}
}
// 事件定義
public class UserCreatedEvent extends ApplicationEvent {
private final User user;
public UserCreatedEvent(Object source, User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
}案例2:復(fù)雜的業(yè)務(wù)場景循環(huán)依賴
/**
* 電商系統(tǒng)中的復(fù)雜循環(huán)依賴場景
*/
@Service
public class ProductService {
@Autowired
private CategoryService categoryService;
@Autowired
private InventoryService inventoryService;
@Autowired
private PriceService priceService;
public ProductDTO getProductDetails(Long productId) {
Product product = productRepository.findById(productId);
// 獲取分類信息
Category category = categoryService.getCategoryWithProducts(product.getCategoryId());
// 獲取庫存信息
Inventory inventory = inventoryService.getInventoryWithProductInfo(productId);
// 獲取價格信息
Price price = priceService.getPriceWithProductDetails(productId);
return ProductDTO.builder()
.product(product)
.category(category)
.inventory(inventory)
.price(price)
.build();
}
}
@Service
public class CategoryService {
@Autowired
private ProductService productService; // 循環(huán)依賴
public Category getCategoryWithProducts(Long categoryId) {
Category category = categoryRepository.findById(categoryId);
// 獲取分類下的熱門產(chǎn)品
List<ProductDTO> hotProducts = productService.getHotProductsByCategory(categoryId);
category.setHotProducts(hotProducts);
return category;
}
}
@Service
public class InventoryService {
@Autowired
private ProductService productService; // 循環(huán)依賴
public Inventory getInventoryWithProductInfo(Long productId) {
Inventory inventory = inventoryRepository.findByProductId(productId);
// 獲取產(chǎn)品基本信息用于庫存展示
ProductDTO productInfo = productService.getBasicProductInfo(productId);
inventory.setProductInfo(productInfo);
return inventory;
}
}解決方案:使用Repository模式和DTO組裝器
/**
* 重構(gòu)后的解決方案:分離數(shù)據(jù)訪問和業(yè)務(wù)邏輯
*/
@Service
public class ProductQueryService {
@Autowired
private ProductRepository productRepository;
@Autowired
private CategoryRepository categoryRepository;
@Autowired
private InventoryRepository inventoryRepository;
@Autowired
private PriceRepository priceRepository;
@Autowired
private ProductDTOAssembler productDTOAssembler;
/**
* 獲取完整的產(chǎn)品信息,避免循環(huán)依賴
*/
public ProductDTO getProductDetails(Long productId) {
// 1. 獲取基礎(chǔ)數(shù)據(jù)
Product product = productRepository.findById(productId);
Category category = categoryRepository.findById(product.getCategoryId());
Inventory inventory = inventoryRepository.findByProductId(productId);
Price price = priceRepository.findByProductId(productId);
// 2. 組裝DTO
return productDTOAssembler.assemble(product, category, inventory, price);
}
}
@Component
public class ProductDTOAssembler {
public ProductDTO assemble(Product product, Category category,
Inventory inventory, Price price) {
return ProductDTO.builder()
.id(product.getId())
.name(product.getName())
.description(product.getDescription())
.categoryName(category.getName())
.categoryPath(category.getPath())
.stockQuantity(inventory.getQuantity())
.availableQuantity(inventory.getAvailableQuantity())
.currentPrice(price.getCurrentPrice())
.originalPrice(price.getOriginalPrice())
.build();
}
public CategoryDTO assembleWithProducts(Category category, List<Product> products) {
return CategoryDTO.builder()
.id(category.getId())
.name(category.getName())
.path(category.getPath())
.productCount(products.size())
.products(products.stream()
.map(this::toSimpleProductDTO)
.collect(Collectors.toList()))
.build();
}
private SimpleProductDTO toSimpleProductDTO(Product product) {
return SimpleProductDTO.builder()
.id(product.getId())
.name(product.getName())
.build();
}
}
// 專門的查詢服務(wù),避免循環(huán)依賴
@Service
public class CategoryQueryService {
@Autowired
private CategoryRepository categoryRepository;
@Autowired
private ProductRepository productRepository;
@Autowired
private ProductDTOAssembler assembler;
public CategoryDTO getCategoryWithProducts(Long categoryId) {
Category category = categoryRepository.findById(categoryId);
List<Product> products = productRepository.findByCategoryId(categoryId);
return assembler.assembleWithProducts(category, products);
}
}監(jiān)控和診斷工具
1. 自定義循環(huán)依賴監(jiān)控
@Component
public class CircularDependencyMonitor {
private static final Logger logger = LoggerFactory.getLogger(CircularDependencyMonitor.class);
private final Map<String, Long> beanCreationTimes = new ConcurrentHashMap<>();
private final Map<String, Set<String>> dependencyChains = new ConcurrentHashMap<>();
@EventListener
public void onBeanCreationStart(BeanCreationStartEvent event) {
String beanName = event.getBeanName();
beanCreationTimes.put(beanName, System.currentTimeMillis());
// 記錄依賴鏈
recordDependencyChain(beanName, event.getDependencyChain());
}
@EventListener
public void onBeanCreationEnd(BeanCreationEndEvent event) {
String beanName = event.getBeanName();
Long startTime = beanCreationTimes.remove(beanName);
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
if (duration > 1000) { // 超過1秒的Bean創(chuàng)建
logger.warn("Bean {} 創(chuàng)建耗時過長: {}ms, 可能存在循環(huán)依賴", beanName, duration);
// 分析依賴鏈
analyzeDependencyChain(beanName);
}
}
}
private void recordDependencyChain(String beanName, Set<String> chain) {
dependencyChains.put(beanName, new HashSet<>(chain));
}
private void analyzeDependencyChain(String beanName) {
Set<String> chain = dependencyChains.get(beanName);
if (chain != null && chain.size() > 3) {
logger.warn("Bean {} 的依賴鏈較長: {}", beanName, chain);
// 檢測是否存在循環(huán)
if (detectCircularInChain(chain)) {
logger.error("檢測到循環(huán)依賴: {}", chain);
}
}
}
private boolean detectCircularInChain(Set<String> chain) {
// 簡化的循環(huán)檢測邏輯
return chain.size() != new HashSet<>(chain).size();
}
}2. Spring Boot Actuator集成
@Component
@Endpoint(id = "circular-dependencies")
public class CircularDependencyEndpoint {
@Autowired
private ApplicationContext applicationContext;
@ReadOperation
public Map<String, Object> circularDependencies() {
Map<String, Object> result = new HashMap<>();
// 分析所有Bean的依賴關(guān)系
Map<String, Set<String>> dependencyGraph = buildDependencyGraph();
// 檢測循環(huán)依賴
List<List<String>> cycles = detectAllCycles(dependencyGraph);
result.put("totalBeans", dependencyGraph.size());
result.put("circularDependencies", cycles);
result.put("affectedBeans", cycles.stream()
.flatMap(List::stream)
.distinct()
.count());
return result;
}
private Map<String, Set<String>> buildDependencyGraph() {
Map<String, Set<String>> graph = new HashMap<>();
if (applicationContext instanceof ConfigurableApplicationContext) {
ConfigurableListableBeanFactory beanFactory =
((ConfigurableApplicationContext) applicationContext).getBeanFactory();
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
try {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
Set<String> dependencies = extractDependencies(bd);
graph.put(beanName, dependencies);
} catch (Exception e) {
// 忽略無法分析的Bean
}
}
}
return graph;
}
private List<List<String>> detectAllCycles(Map<String, Set<String>> graph) {
List<List<String>> cycles = new ArrayList<>();
Set<String> visited = new HashSet<>();
for (String node : graph.keySet()) {
if (!visited.contains(node)) {
List<String> path = new ArrayList<>();
Set<String> pathSet = new HashSet<>();
findCycles(graph, node, visited, path, pathSet, cycles);
}
}
return cycles;
}
private void findCycles(Map<String, Set<String>> graph, String current,
Set<String> visited, List<String> path,
Set<String> pathSet, List<List<String>> cycles) {
if (pathSet.contains(current)) {
// 找到循環(huán)
int cycleStart = path.indexOf(current);
List<String> cycle = new ArrayList<>(path.subList(cycleStart, path.size()));
cycle.add(current);
cycles.add(cycle);
return;
}
if (visited.contains(current)) {
return;
}
visited.add(current);
path.add(current);
pathSet.add(current);
Set<String> neighbors = graph.get(current);
if (neighbors != null) {
for (String neighbor : neighbors) {
findCycles(graph, neighbor, visited, path, pathSet, cycles);
}
}
path.remove(path.size() - 1);
pathSet.remove(current);
}
private Set<String> extractDependencies(BeanDefinition beanDefinition) {
// 實(shí)現(xiàn)依賴提取邏輯
Set<String> dependencies = new HashSet<>();
// 提取構(gòu)造器依賴
ConstructorArgumentValues constructorArgs = beanDefinition.getConstructorArgumentValues();
extractDependenciesFromConstructorArgs(constructorArgs, dependencies);
// 提取屬性依賴
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
extractDependenciesFromPropertyValues(propertyValues, dependencies);
return dependencies;
}
}3. 性能監(jiān)控和優(yōu)化
@Component
public class CircularDependencyPerformanceMonitor {
private final MeterRegistry meterRegistry;
private final Timer.Sample sample;
public CircularDependencyPerformanceMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.sample = Timer.start(meterRegistry);
}
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
sample.stop(Timer.builder("spring.context.startup.time")
.description("Spring context startup time")
.register(meterRegistry));
// 分析啟動過程中的循環(huán)依賴處理
analyzeStartupPerformance();
}
private void analyzeStartupPerformance() {
ApplicationContext context = applicationContext;
// 統(tǒng)計Bean創(chuàng)建耗時
Map<String, Long> beanCreationTimes = getBeanCreationTimes();
// 識別耗時最長的Bean
String slowestBean = beanCreationTimes.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("unknown");
Long slowestTime = beanCreationTimes.get(slowestBean);
// 記錄指標(biāo)
Gauge.builder("spring.bean.creation.slowest.time")
.description("Slowest bean creation time")
.register(meterRegistry, slowestTime);
Counter.builder("spring.circular.dependencies.resolved")
.description("Number of circular dependencies resolved")
.register(meterRegistry)
.increment(countResolvedCircularDependencies());
}
private Map<String, Long> getBeanCreationTimes() {
// 實(shí)現(xiàn)Bean創(chuàng)建時間統(tǒng)計
return new HashMap<>();
}
private int countResolvedCircularDependencies() {
// 統(tǒng)計解決的循環(huán)依賴數(shù)量
return 0;
}
}最佳實(shí)踐總結(jié)
1. 設(shè)計原則
/**
* 避免循環(huán)依賴的設(shè)計原則
*/
public class CircularDependencyBestPractices {
/**
* 1. 單一職責(zé)原則
* 每個類應(yīng)該只有一個明確的職責(zé),避免過度耦合
*/
@Service
public class UserService {
// 只負(fù)責(zé)用戶相關(guān)的核心業(yè)務(wù)邏輯
public User createUser(CreateUserRequest request) {
// 用戶創(chuàng)建邏輯
}
}
/**
* 2. 依賴倒置原則
* 依賴抽象而不是具體實(shí)現(xiàn)
*/
@Service
public class OrderService {
// 依賴接口而不是具體實(shí)現(xiàn)
private final UserRepository userRepository;
private final NotificationSender notificationSender;
public OrderService(UserRepository userRepository,
NotificationSender notificationSender) {
this.userRepository = userRepository;
this.notificationSender = notificationSender;
}
}
/**
* 3. 接口隔離原則
* 使用小而專一的接口
*/
public interface UserValidator {
boolean validateUser(User user);
}
public interface OrderValidator {
boolean validateOrder(Order order);
}
/**
* 4. 事件驅(qū)動架構(gòu)
* 使用事件解耦服務(wù)間的直接依賴
*/
@Service
public class EventDrivenUserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public User createUser(CreateUserRequest request) {
User user = new User(request);
user = userRepository.save(user);
// 發(fā)布事件而不是直接調(diào)用其他服務(wù)
eventPublisher.publishEvent(new UserCreatedEvent(user));
return user;
}
}
}2. 代碼檢查清單
/**
* 循環(huán)依賴檢查清單
*/
public class CircularDependencyChecklist {
/**
* 檢查項目:
*
* 1. 構(gòu)造器注入檢查
* - 避免構(gòu)造器循環(huán)依賴
* - 使用@Lazy注解打破循環(huán)
*
* 2. 服務(wù)層設(shè)計檢查
* - 服務(wù)職責(zé)是否單一
* - 是否存在相互調(diào)用
*
* 3. 依賴關(guān)系檢查
* - 依賴層次是否清晰
* - 是否違反分層架構(gòu)原則
*
* 4. 配置檢查
* - Bean作用域是否合適
* - 是否正確使用@Lazy
*
* 5. 測試覆蓋
* - 是否有集成測試覆蓋循環(huán)依賴場景
* - 是否有性能測試驗(yàn)證啟動時間
*/
public void performChecklist() {
checkConstructorDependencies();
checkServiceLayerDesign();
checkDependencyHierarchy();
checkConfiguration();
checkTestCoverage();
}
private void checkConstructorDependencies() {
// 檢查構(gòu)造器循環(huán)依賴
}
private void checkServiceLayerDesign() {
// 檢查服務(wù)層設(shè)計
}
private void checkDependencyHierarchy() {
// 檢查依賴層次
}
private void checkConfiguration() {
// 檢查配置
}
private void checkTestCoverage() {
// 檢查測試覆蓋率
}
}結(jié)論
Spring通過精妙的三級緩存機(jī)制成功解決了單例Bean的循環(huán)依賴問題,這一設(shè)計體現(xiàn)了Spring框架的深度思考和技術(shù)實(shí)力。理解這一機(jī)制不僅有助于我們更好地使用Spring,還能幫助我們:
關(guān)鍵要點(diǎn)回顧
- 三級緩存的作用:
- 一級緩存:存儲完全初始化的Bean
- 二級緩存:存儲早期Bean引用,解決循環(huán)依賴
- 三級緩存:存儲Bean工廠,處理AOP代理
- 解決原理:
- 在Bean實(shí)例化后立即暴露早期引用
- 通過工廠模式延遲決定是否創(chuàng)建代理
- 確保循環(huán)依賴中對象引用的一致性
- 限制條件:
- 只能解決單例Bean的setter注入循環(huán)依賴
- 無法解決構(gòu)造器循環(huán)依賴
- 無法解決prototype作用域的循環(huán)依賴
- 最佳實(shí)踐:
- 優(yōu)先使用setter注入而非構(gòu)造器注入
- 合理使用@Lazy注解
- 采用事件驅(qū)動架構(gòu)解耦服務(wù)
- 遵循SOLID設(shè)計原則
實(shí)際應(yīng)用建議
在實(shí)際開發(fā)中,我們應(yīng)該:
- 預(yù)防為主:通過良好的架構(gòu)設(shè)計避免循環(huán)依賴
- 監(jiān)控診斷:使用工具監(jiān)控和診斷循環(huán)依賴問題
- 性能優(yōu)化:關(guān)注循環(huán)依賴對啟動性能的影響
- 持續(xù)改進(jìn):定期重構(gòu)代碼,消除不必要的依賴關(guān)系
Spring的循環(huán)依賴解決方案是一個經(jīng)典的工程實(shí)踐案例,它告訴我們:面對復(fù)雜的技術(shù)問題,往往需要巧妙的設(shè)計和精細(xì)的實(shí)現(xiàn)。掌握這些知識不僅能幫助我們更好地使用Spring框架,還能提升我們的系統(tǒng)設(shè)計能力。
到此這篇關(guān)于Spring如何解決循環(huán)依賴:深入理解三級緩存機(jī)制的文章就介紹到這了,更多相關(guān)Spring循環(huán)依賴三級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Spring Boot Mysql 版本驅(qū)動連接池方案選擇
這篇文章主要介紹了詳解Spring Boot Mysql 版本驅(qū)動連接池方案選擇,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
Intellij IDEA 添加jar包的三種方式(小結(jié))
這篇文章主要介紹了Intellij IDEA 添加jar包的三種方式(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
解決使用@ManyToMany查詢數(shù)據(jù)時的死循環(huán)問題
這篇文章主要介紹了解決使用@ManyToMany查詢數(shù)據(jù)時的死循環(huán)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Java8中創(chuàng)建Stream流的幾種常見方式
在Java 8中,??Stream?? API 是一種新的處理數(shù)據(jù)的方式,它允許以聲明式的方式來處理數(shù)據(jù)集合,本文將詳細(xì)介紹在Java 8中創(chuàng)建 ??Stream?? 流的幾種常見方式,大家可以根據(jù)需要進(jìn)行選擇2025-05-05
java遞歸與非遞歸實(shí)現(xiàn)掃描文件夾下所有文件
這篇文章主要為大家詳細(xì)介紹了java遞歸與非遞歸實(shí)現(xiàn)掃描文件夾下所有文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02
SpringBoot整合EasyExcel實(shí)現(xiàn)大規(guī)模數(shù)據(jù)的并行導(dǎo)出與壓縮下載
在 Spring Boot 應(yīng)用中,整合 EasyExcel 實(shí)現(xiàn)并行導(dǎo)出數(shù)據(jù)并進(jìn)行 Zip 壓縮下載可以極大地提高數(shù)據(jù)處理效率和用戶體驗(yàn),文中通過代碼示例介紹的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下2024-10-10
Java數(shù)據(jù)結(jié)構(gòu)之線索化二叉樹的實(shí)現(xiàn)
在二叉樹的結(jié)點(diǎn)上加上線索的二叉樹稱為線索二叉樹,對二叉樹以某種遍歷方式進(jìn)行遍歷,使其變?yōu)榫€索二叉樹的過程稱為對二叉樹進(jìn)行線索化。本文將詳解如何實(shí)現(xiàn)線索化二叉樹,需要的可以參考一下2022-05-05

