【Spring系列-02】IoC 容器与依赖注入源码剖析
一、概念
Spring开发中,@Autowired自动注入依赖、循环依赖时成功与报错的差异,均与IoC容器和依赖注入机制相关。深入源码可帮助理解并解决这些问题。
二、BeanFactory与ApplicationContext的继承体系
(一)功能边界
| 核心接口 | BeanFactory职责 | ApplicationContext职责 |
|---|---|---|
| ListableBeanFactory | 按类型或名称获取Bean定义列表,查询符合条件的Bean定义。 | 继承该接口功能,新增国际化、事件发布等扩展功能。 |
| HierarchicalBeanFactory | 支持父子BeanFactory结构,可获取父BeanFactory。 | 继承该结构管理能力,增强上下文层次结构支持。 |
(二)ApplicationContext为何是BeanFactory的超集
Spring Framework 6.x中,AbstractApplicationContext封装BeanFactory,实现其接口并扩展资源加载、国际化等功能。核心源码显示其通过持有ConfigurableListableBeanFactory实例,在obtainFreshBeanFactory方法中创建管理,实现功能扩展。
// AbstractApplicationContext部分源码
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
private ConfigurableListableBeanFactory beanFactory;
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
}
(三)实战
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
public class BeanFactoryVsApplicationContext {
public static void main(String[] args) {
// BeanFactory获取Bean
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
Object beanFromBeanFactory = beanFactory.getBean("exampleBean");
// ApplicationContext获取Bean
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Object beanFromApplicationContext = applicationContext.getBean("exampleBean");
}
}
两者均可获取exampleBean,但ApplicationContext提供自动装配、国际化等更丰富功能。
流程图(BeanFactory与ApplicationContext继承关系)
三、BeanDefinition加载与解析流程
(一)资源定位→解析→注册全流程
Spring 6.x中XmlBeanDefinitionReader的doLoadBeanDefinitions是核心方法:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
} catch (Exception ex) {
// 异常处理
}
}
- 资源定位:通过
Resource接口(如ClassPathResource)定位配置文件。 - 解析:
DocumentLoader转换资源为Document,再由BeanDefinitionParserDelegate提取信息。 - 注册:解析后的
BeanDefinition注册到BeanDefinitionRegistry(如DefaultListableBeanFactory)。
(二)关键数据解析
- propertyValues属性:解析
<property>标签值,创建PropertyValue存入集合。 - scope属性:解析
<bean>的scope值(如singleton),设置到BeanDefinition的scope字段。
(三)协作时序图
四、循环依赖源码分析与解决方案
(一)复现循环依赖场景
- 构造器注入循环依赖:
public class A { private B b; public A(B b) { this.b = b; } }
public class B { private A a; public B(A a) { this.a = a; } }
- setter注入循环依赖:
public class C { private D d; public void setD(D d) { this.d = d; } }
public class D { private C c; public void setC(C c) { this.c = c; } }
- 多例Bean循环依赖:
scope="prototype"的Bean默认不支持循环依赖,会抛异常。
(二)Spring处理循环依赖的判定标准
DefaultSingletonBeanRegistry的beforeSingletonCreation方法检测循环依赖:
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) &&!this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
Bean创建时加入singletonsCurrentlyInCreation集合,重复创建则抛异常。isDependent方法检查依赖关系。
(三)实战
通过自定义BeanPostProcessor验证循环依赖处理时机:
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前检查循环依赖: " + beanName);
return bean;
}
}
断点可设在AbstractAutowireCapableBeanFactory的resolveCircularReference方法。
流程图(循环依赖检测流程)
五、三级缓存设计原理
(一)三级缓存源码定义与交互逻辑
DefaultSingletonBeanRegistry中定义三级缓存:
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 完全初始化Bean
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 提前暴露Bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 单例Bean工厂
获取Bean时依次从三级缓存查询:先singletonObjects,再earlySingletonObjects,最后通过singletonFactories创建提前暴露Bean。
(二)为什么需要三级缓存而非两级
两级缓存缺少singletonFactories时,提前暴露的Bean无法经BeanPostProcessor处理。singletonFactories缓存工厂对象,通过getObject方法获取SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference处理后的Bean,解决循环依赖。
(三)状态流转图
六、Bean创建流程的关键扩展点
(一)按Bean生命周期顺序列出扩展点
- 实例化阶段:
InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation,实例化前调用,可返回代理对象。 - 初始化阶段:
BeanPostProcessor的postProcessAfterInitialization,初始化后调用,可增强Bean(如AOP代理)。
(二)源码定位
- 实例化阶段:
AbstractAutowireCapableBeanFactory的createBean调用applyBeanPostProcessorsBeforeInstantiation。 - 初始化阶段:
AbstractAutowireCapableBeanFactory的initializeBean调用applyBeanPostProcessorsAfterInitialization。
(三)实战
自定义BeanPostProcessor处理属性加密解密:
@Component
public class EncryptionBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof EncryptableBean) {
((EncryptableBean) bean).setEncryptedProperty(decrypt(((EncryptableBean) bean).getEncryptedProperty()));
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof EncryptableBean) {
((EncryptableBean) bean).setEncryptedProperty(encrypt(((EncryptableBean) bean).getEncryptedProperty()));
}
return bean;
}
// 加密解密方法省略
}
七、源码级定制化
(一)自定义BeanDefinitionReader解析JSON配置
继承AbstractBeanDefinitionReader实现JSON解析:
public class JsonBeanDefinitionReader extends AbstractBeanDefinitionReader {
public JsonBeanDefinitionReader(DefaultListableBeanFactory beanFactory) { super(beanFactory); }
@Override
public int loadBeanDefinitions(Resource... resources) {
int count = 0;
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
public int loadBeanDefinitions(Resource resource) {
// 解析JSON并注册BeanDefinition,逻辑省略
return 1;
}
}
注册到容器:
public class JsonConfigApp {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
JsonBeanDefinitionReader reader = new JsonBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("config.json"));
ApplicationContext context = new GenericApplicationContext(beanFactory);
}
}
(二)扩展DefaultListableBeanFactory实现超时控制
public class TimeoutAwareBeanFactory extends DefaultListableBeanFactory {
private long timeout = 1000;
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws Exception {
long startTime = System.nanoTime();
try {
return super.createBean(beanName, mbd, args);
} finally {
long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
if (elapsed > timeout) {
throw new RuntimeException("Bean创建超时: " + beanName);
}
}
}
}
八、推荐源码学习路线图
- 基础入手:从
BeanFactory及DefaultListableBeanFactory开始,掌握Bean注册与获取逻辑。 - 加载流程:研究
BeanDefinition加载解析,重点关注XmlBeanDefinitionReader或AnnotationConfigApplicationContext。 - 循环依赖与缓存:学习循环依赖处理及三级缓存原理,研读
DefaultSingletonBeanRegistry相关方法。 - 扩展点与生命周期:探究
BeanPostProcessor等扩展点及调用时机,梳理Bean完整生命周期对应源码。 - 高级定制:尝试自定义
BeanDefinitionReader、扩展DefaultListableBeanFactory,深化对容器扩展性的理解。