
不堆砌代码,只抓核心脉络 —— 带你读懂Spring最精髓的设计
在传统Java开发中,对象之间的依赖关系由开发者手动管理:new Service(new Dao())。这种硬编码导致耦合度高、单元测试困难、扩展性差。
Spring IoC(Inversion of Control)容器扭转了控制权——由容器负责对象的创建、组装和生命周期管理,开发者只需声明“我需要什么”,容器自动注入。这一思想奠定了Spring生态的基石。
Spring容器管理的每个对象都被抽象为一个 BeanDefinition,它存储了该Bean的所有元信息:
// 简化版BeanDefinition核心字段
public class BeanDefinition {
private String beanClassName;
private String scope = "singleton";
private boolean lazyInit = false;
private List<PropertyValue> propertyValues;
private ConstructorArgumentValues constructorArguments;
// ...
}容器本质上就是一个 Map<String, BeanDefinition>,外加一个单例缓存池。
new AnnotationConfigApplicationContext(AppConfig.class);这行代码背后经历了三个关键阶段:
@ComponentScan 指定的包路径,通过 ClassPathBeanDefinitionScanner 扫描所有带 @Component 的类。@Scope、@Lazy、@Primary 等注解,生成 BeanDefinition 并注册到容器。BeanFactoryPostProcessor 修改 BeanDefinition 元数据(例如替换占位符 @Value("${jdbc.url}"))。PropertySourcesPlaceholderConfigurer 在此阶段完成配置文件的解析。这是最复杂的阶段,也是面试高频区。Spring 会遍历所有非懒加载的 Singleton Bean,依次执行:
实例化(构造器/工厂方法)
→ 属性填充(依赖注入)
→ 感知接口回调(BeanNameAware, BeanFactoryAware...)
→ 前置初始化(BeanPostProcessor.beforeInitialization)
→ 执行初始化方法(@PostConstruct, InitializingBean)
→ 后置初始化(BeanPostProcessor.afterInitialization)
→ 放入单例缓存池源码中 AbstractAutowireCapableBeanFactory.createBean() 最终调用 doCreateBean(),其中两处最值得关注:
// 源码简化
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);Spring 根据 @Autowired 标注的构造器或默认无参构造器,通过 CGLIB 或 Javassist 或反射生成对象实例(此时对象内部的属性均为 null)。
populateBean(beanName, mbd, instanceWrapper);这里会遍历 PropertyValues,对每个依赖的属性调用 resolveValueIfNecessary()。如果依赖的是另一个Bean,则触发 getBean() —— 这可能导致循环依赖。
Spring 通过 三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)巧妙解决单例模式的循环依赖,其核心思想是 提前暴露未完成实例化的对象引用。
// 三级缓存的核心获取逻辑(简化)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}注:仅单例且允许循环依赖时,三级缓存生效。原型(Prototype)Bean 遇到循环依赖会直接抛出异常。
这是Spring留给开发者最强大的扩展点。 几乎所有的AOP、事务管理、数据源代理、自定义注解驱动,都是通过实现 BeanPostProcessor 接口完成的。
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 在初始化前修改或包装bean
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 返回代理对象(例如AOP返回的JDK动态代理)
return Proxy.newProxyInstance(...);
}
}Spring 内部大量使用该机制:
AutowiredAnnotationBeanPostProcessor 处理 @Autowired 和 @ValueAnnotationAwareAspectJAutoProxyCreator 实现基于注解的AOPSpring 的设计哲学是 让容器隐藏于幕后。你编写的业务类不需要继承任何Spring类,只需标注注解即可被管理。这得益于:
getBean(Class) 替代了早期的字符串查找。@Conditional)让配置更具弹性。设计模式 | Spring中的应用 |
|---|---|
工厂模式 | BeanFactory、ApplicationContext |
模板方法 | AbstractApplicationContext.refresh() 定义启动流程骨架,子类实现具体步骤 |
策略模式 | 多种Bean实例化策略(构造器、静态工厂、实例工厂) |
代理模式 | AOP、事务管理、缓存抽象 |
观察者模式 | 事件发布监听(ApplicationEvent / ApplicationListener) |
Spring IOC 容器远不止是一个“Map+反射”的工具,它是一个 可扩展、可插拔、生命周期完备的轻量级微内核。理解其源码,不在于记住每一行代码,而在于领悟 如何用分层抽象、后置处理器、缓存机制来构建一个松耦合的系统。
真正的收获是:
一个好的框架,应当让业务代码干净纯粹,而把复杂性封装在优雅的扩展点背后。
这,正是Spring源码教给我们最宝贵的设计智慧。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。