bean的加载(九)记录创建bean的ObjectFactory

本文探讨了Spring框架在创建bean时的早期单例暴露(earlySingletonExposure)概念,分析了其是否为单例、是否允许循环依赖以及bean是否正在创建的影响因素。在满足特定条件时,Spring会将bean的ObjectFactory添加到缓存中,以处理循环依赖情况。通过ObjectFactory,Spring避免了在属性填充过程中重复实例化bean,确保了正确创建带有循环依赖的bean。接下来的内容将深入研究populateBean方法在属性填充过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在doCreateBean中有这样一段代码:

//是否需要提早曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
			//依赖处理:在Spring中会有循环依赖的情况,例如,当A中含有B的属性,而B中又含有A的属性时就会
			//构成一个循环依赖,此时如果A和B都是单例,那么在Spring中的处理方式就是当创建B的时候,涉及
			//自动注入A的步骤时,并不是直接去再次创建A,而是通过放入缓存中的ObjectFactory来创建实例,
			//这样就解决了循环依赖的问题。
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				public Object getObject() throws BeansException {
					//对bean再一次依赖引用,主要应用SmartInstantiationAware BeanPostProcessor,
					//其中我们熟知的AOP就是在这里将advice动态植入bean中,若没有则直接返回bean,不做任何处理
					return getEarlyBeanReference(beanName, mbd, b
<think>嗯,用户想了解Spring Bean的延迟加载配置方法和原理。我先回忆一下相关知识:延迟加载是指Spring容器启动时不立即初始化某些Bean,而是在首次使用时才创建。这能提升启动速度,特别适合资源消耗大的Bean。 用户给出的引用材料很有帮助。引用[2]明确提到XML配置方式:在<bean>标签添加lazy-init="true"属性。引用[3]补充了注解方式:在类上使用@Lazy注解。需要特别注意引用[4]指出的依赖关系问题——如果延迟加载Bean被非延迟Bean依赖,它仍会立即初始化。 关于原理部分,引用[1]和引用[5]形成对比:ApplicationContext默认预初始化单例Bean,而BeanFactory天生就是延迟加载的。这里可以结合Spring源码说明AbstractApplicationContext.refresh()方法中的finishBeanFactoryInitialization()环节负责初始化非延迟单例Bean。 用户可能还需要知道实际应用场景。根据引用[3],初始化耗时的Bean(如数据库连接池)适合延迟加载,但要注意引用[4]强调的依赖链问题。另外想到可以补充:Spring Boot的@Lazy还能配合@Autowired使用解决循环依赖。 最后需要提醒配置陷阱:prototype作用域的Bean天然延迟,lazy-init对其无效(引用[5]);web环境中延迟加载可能导致首次请求响应延迟。这些在生成回答时都要涵盖。</think>Spring Bean的延迟加载机制允许在容器启动时推迟Bean的初始化,在首次请求时才创建实例。以下是详细配置方法及原理分析: ### 一、配置方法 #### 1. XML配置 在`<bean>`标签中添加`lazy-init="true"`属性: ```xml <bean id="lazyBean" class="com.example.LazyService" lazy-init="true" /> ``` #### 2. 注解配置 在类上使用`@Lazy`注解: ```java @Component @Lazy // 延迟加载Bean public class DatabaseConnector { // ... } ``` #### 3. Java配置类 在`@Bean`方法上添加`@Lazy`: ```java @Configuration public class AppConfig { @Bean @Lazy public HeavyResource heavyResource() { return new HeavyResource(); } } ``` ### 二、核心原理 1. **容器初始化行为差异**: - `ApplicationContext`默认**立即加载**所有单例Bean(`lazy-init="false"`),在`refresh()`阶段通过`finishBeanFactoryInitialization()`方法预初始化[^1][^2]。 - 延迟加载Bean在首次调用`getBean()`时触发初始化,由`DefaultSingletonBeanRegistry.getSingleton()`实现按需创建[^1][^4]。 2. **依赖关系的影响**: - 若**非延迟Bean依赖延迟Bean**(如`A->B`且B为`@Lazy`),容器会**强制立即初始化B**以满足依赖[^2][^4]。 - **原型作用域(prototype)Bean**天然延迟,不受`lazy-init`配置影响[^5]。 3. **作用域与延迟加载**: ```mermaid graph LR A[Bean作用域] --> B[单例 singleton] A --> C[原型 prototype] B --> D{是否延迟?} D -- lazy-init=true --> E[首次getBean时初始化] D -- lazy-init=false --> F[容器启动时初始化] C --> G[始终延迟初始化] ``` ### 三、应用场景与注意事项 1. **适用场景**: - 初始化耗时的Bean(如数据库连接池) - 占用内存大的辅助类 - 某些需要按需加载的工具服务 2. **典型陷阱**: ```java @Service public class ImmediateService { @Autowired // 导致LazyService被强制立即初始化! private LazyService lazyService; } ``` 解决方案:在注入点添加`@Lazy`: ```java @Autowired @Lazy // 延迟注入代理对象 private LazyService lazyService; ``` 3. **性能权衡**: - ✅ 减少启动时间 - ⚠️ 首次请求可能响应延迟 - ⚠️ 可能掩盖循环依赖问题 > **源码关键路径**:延迟加载Bean在`AbstractBeanFactory.doGetBean()`中通过`getSingleton(String beanName, ObjectFactory<?> singletonFactory)`实现按需创建[^1][^4]。Spring通过生成代理对象占位,实际调用时触发初始化。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值