欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring解決循環(huán)依賴的方法及三級緩存機(jī)制實(shí)踐案例

 更新時間:2025年09月20日 12:05:13   作者:塔中妖  
Spring通過三級緩存解決單例Bean循環(huán)依賴,但無法處理構(gòu)造器、prototype作用域及@Async場景,建議使用setter注入、@Lazy注解和架構(gòu)優(yōu)化,遵循設(shè)計原則避免依賴問題,本文介紹Spring如何解決循環(huán)依賴:深入理解三級緩存機(jī)制,感興趣的朋友一起看看吧

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)該:

  1. 預(yù)防為主:通過良好的架構(gòu)設(shè)計避免循環(huán)依賴
  2. 監(jiān)控診斷:使用工具監(jiān)控和診斷循環(huán)依賴問題
  3. 性能優(yōu)化:關(guān)注循環(huán)依賴對啟動性能的影響
  4. 持續(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ū)動連接池方案選擇

    這篇文章主要介紹了詳解Spring Boot Mysql 版本驅(qū)動連接池方案選擇,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Intellij IDEA 添加jar包的三種方式(小結(jié))

    Intellij IDEA 添加jar包的三種方式(小結(jié))

    這篇文章主要介紹了Intellij IDEA 添加jar包的三種方式(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • 解決使用@ManyToMany查詢數(shù)據(jù)時的死循環(huán)問題

    解決使用@ManyToMany查詢數(shù)據(jù)時的死循環(huán)問題

    這篇文章主要介紹了解決使用@ManyToMany查詢數(shù)據(jù)時的死循環(huán)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java8中創(chuàng)建Stream流的幾種常見方式

    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)掃描文件夾下所有文件

    java遞歸與非遞歸實(shí)現(xiàn)掃描文件夾下所有文件

    這篇文章主要為大家詳細(xì)介紹了java遞歸與非遞歸實(shí)現(xiàn)掃描文件夾下所有文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 排序算法的Java實(shí)現(xiàn)全攻略

    排序算法的Java實(shí)現(xiàn)全攻略

    這篇文章主要介紹了排序算法的Java實(shí)現(xiàn),包括Collections.sort()的使用以及各種經(jīng)典算法的Java代碼實(shí)現(xiàn)方法總結(jié),超級推薦!需要的朋友可以參考下
    2015-08-08
  • 關(guān)于ArrayList初始化容量的問題

    關(guān)于ArrayList初始化容量的問題

    這篇文章主要介紹了關(guān)于ArrayList初始化容量的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 如何把springboot jar項目 改為war項目

    如何把springboot jar項目 改為war項目

    這篇文章主要介紹了如何把springboot jar項目 改為war項目,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • SpringBoot整合EasyExcel實(shí)現(xiàn)大規(guī)模數(shù)據(jù)的并行導(dǎo)出與壓縮下載

    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)

    Java數(shù)據(jù)結(jié)構(gòu)之線索化二叉樹的實(shí)現(xiàn)

    在二叉樹的結(jié)點(diǎn)上加上線索的二叉樹稱為線索二叉樹,對二叉樹以某種遍歷方式進(jìn)行遍歷,使其變?yōu)榫€索二叉樹的過程稱為對二叉樹進(jìn)行線索化。本文將詳解如何實(shí)現(xiàn)線索化二叉樹,需要的可以參考一下
    2022-05-05

最新評論