1-4-1-spring设计哲学
Spring 框架的设计哲学深刻体现了现代软件工程的核心原则,其源码是这些思想的精妙实践。下面我将结合源码,从三大核心哲学、设计模式应用及实践启示等方面为你解析。
一、控制反转(IoC)与依赖注入(DI)
IoC 是 Spring 的基石,其核心思想是将对象的创建和依赖管理的控制权从应用程序代码反转给容器。依赖注入(DI)是 IoC 的主要实现方式。
1. 容器核心:BeanFactory与 ApplicationContext
BeanFactory是基础接口,定义了容器的基本行为,如getBean()。ApplicationContext是其子接口,扩展了企业级功能(如国际化、事件发布、资源加载)。- 源码定位:
ApplicationContext接口继承了ListableBeanFactory,HierarchicalBeanFactory,MessageSource,ApplicationEventPublisher等接口,整合了多种能力。
2. 容器初始化流程:AbstractApplicationContext.refresh()
这是容器启动的核心方法,定义了初始化的骨架(模板方法模式),主要步骤包括:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新上下文
prepareRefresh();
// 2. 获取刷新后的BeanFactory,加载并注册BeanDefinitions
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备BeanFactory(配置标准上下文,如ClassLoader)
prepareBeanFactory(beanFactory);
try {
// 4. 允许子类上下文对BeanFactory进行后置处理
postProcessBeanFactory(beanFactory);
// 5. 执行BeanFactoryPostProcessor(修改Bean定义)
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册BeanPostProcessor(拦截Bean的创建过程)
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源
initMessageSource();
// 8. 初始化事件多播器
initApplicationEventMulticaster();
// 9. 初始化子类特殊Bean
onRefresh();
// 10. 注册事件监听器
registerListeners();
// 11. 实例化所有非懒加载单例Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新过程
finishRefresh();
} catch (BeansException ex) {
// ... 异常处理与销毁
}
}
}
这个过程体现了 “约定优于配置” 和 “分层架构” 思想,框架定义了主干流程,同时通过 BeanFactoryPostProcessor和 BeanPostProcessor等扩展点开放了极大的灵活性。
3. 循环依赖的解决:三级缓存
Spring 通过三级缓存机智地解决了单例 Bean 的循环依赖问题:
-
一级缓存
singletonObjects:存储完全初始化好的单例 Bean。 -
二级缓存
earlySingletonObjects:存储提前暴露的早期引用(已实例化但未填充属性)。 -
三级缓存
singletonFactories:存储 Bean 工厂,用于生成早期引用。核心方法
DefaultSingletonBeanRegistry.getSingleton()通过在不同缓存中查找和移动 Bean,确保了循环依赖时的正确注入。
二、面向切面编程(AOP)
AOP 将横切关注点(如日志、事务)与核心业务逻辑分离,通过动态代理实现。
1. 代理机制:JDK 动态代理与 CGLIB
- JDK 动态代理:基于接口。使用
JdkDynamicAopProxy,通过InvocationHandler拦截方法调用。 - CGLIB 代理:基于类继承。使用
ObjenesisCglibAopProxy,生成目标类的子类作为代理。 - 选择策略:在
DefaultAopProxyFactory.createAopProxy()方法中,若目标类实现了接口,默认使用 JDK 代理;否则使用 CGLIB。可通过配置强制使用 CGLIB。
2. 拦截器链与执行流程
当代理方法被调用时,会创建一个 拦截器链(MethodInterceptor列表)。调用过程被封装在 ReflectiveMethodInvocation.proceed()中,该方法会递归调用拦截器链中的每个拦截器,最终调用目标方法。这种设计模式是 责任链模式 的典型应用。
public Object proceed() throws Throwable {
// 如果所有拦截器都已执行,调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个拦截器并执行
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// ... 执行拦截器
}
3. 事务管理:@Transactional
声明式事务是 AOP 的经典应用。其核心拦截器是 TransactionInterceptor,它在 invokeWithinTransaction()方法中:
-
根据
@Transactional的属性获取事务管理器。 -
在方法执行前创建或加入事务。
-
方法执行成功后提交事务。
-
捕获异常并根据规则决定回滚事务。
这体现了 “关注点分离”,开发者无需在业务代码中编写繁琐的事务控制逻辑。
三、模块化与扩展性
Spring 框架采用分层模块化设计,各模块职责单一,并通过丰富的扩展点支持框架演进和定制。
1. 模块化设计
Spring Framework 由多个模块组成,如 spring-core, spring-beans, spring-context, spring-aop, spring-tx, spring-web等。这些模块相互独立,开发者可以按需引入,体现了 “单一职责原则”。
2. 扩展点机制
Spring 提供了多个重要的扩展接口,允许开发者介入容器的生命周期:
-
BeanFactoryPostProcessor:在 Bean 定义加载后、实例化前,允许修改 Bean 的定义(如PropertySourcesPlaceholderConfigurer处理占位符)。 -
BeanPostProcessor:在 Bean 实例化后、初始化前后,允许修改或包装 Bean 实例(如AutowiredAnnotationBeanPostProcessor处理@Autowired注入)。 -
InitializingBean与DisposableBean:管理 Bean 的自定义初始化和销毁逻辑。这些扩展点体现了 “开闭原则”,框架对修改关闭,对扩展开放。
四、设计模式在源码中的应用
Spring 源码是设计模式的典范教科书:
| 设计模式 | 应用场景 | 源码示例 |
|---|---|---|
| 工厂模式 | 创建和管理 Bean | BeanFactory, ApplicationContext |
| 单例模式 | Bean 作用域 | 默认单例,缓存于 singletonObjects |
| 代理模式 | AOP 实现 | JdkDynamicAopProxy, CglibAopProxy |
| 模板方法 | 定义流程骨架 | AbstractApplicationContext.refresh() |
| 观察者模式 | 事件监听 | ApplicationEvent, ApplicationListener |
| 适配器模式 | 统一接口 | AdvisorAdapter(将 Advice 适配为 MethodInterceptor) |
五、Spring 设计哲学的实践启示
- 轻量级与非侵入性:Spring 鼓励使用 POJO(Plain Old Java Object)进行开发,你的业务类通常无需继承或实现任何 Spring 特定的类或接口。框架通过配置(注解或 XML)或后置处理器来增强你的 Bean,这使得应用程序与框架的耦合度降到最低。
- 包容性与集成:Spring 并不旨在取代所有优秀的技术,而是提供一个统一的平台来集成它们(如 JDBC、JPA、Hibernate、Quartz 等),并提供一致的编程模型。例如,
PlatformTransactionManager抽象了各种事务管理器的接口。 - 实践建议:深入理解 Spring 的设计哲学和源码,能帮助你在实际开发中:
- 更好地解决问题:当遇到复杂问题时,可以想到利用 Spring 提供的扩展点(如自定义
BeanPostProcessor)来优雅地解决。 - 进行更高效地调试:熟悉源码流程后,能快速定位框架层面的问题。
- 做出更合理的设计:将 Spring 的设计思想(如解耦、模块化、面向接口编程)应用到自己的项目设计中,提升代码质量。
- 更好地解决问题:当遇到复杂问题时,可以想到利用 Spring 提供的扩展点(如自定义
Spring 通过精妙的代码将抽象的设计理念转化为稳定、灵活、强大的框架功能。希望这些解析能帮助你更深刻地理解 Spring,并在设计和面试中游刃有余。
Spring框架的扩展点机制
Spring框架的扩展点机制是其强大灵活性的核心体现,它允许开发者在不修改框架源码的情况下,深度定制Bean的创建、初始化、配置及容器本身的行为。这种机制主要基于一系列预设的接口和回调方法,Spring在容器的启动和Bean生命周期的不同阶段会自动调用这些接口的实现。
1. BeanFactoryPostProcessor
BeanFactoryPostProcessor接口允许在所有Bean定义(BeanDefinition)已被加载到容器但尚未实例化任何Bean时,对Bean的定义信息进行修改。
-
执行时机:在Spring容器刷新(
refresh()方法)过程中,调用invokeBeanFactoryPostProcessors(beanFactory)时执行。 -
源码示例:
@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 获取所有Bean定义的名称 String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); // 例如:打印所有Bean的名称,或者修改特定Bean定义的属性 System.out.println("Loaded bean definitions: " + Arrays.toString(beanDefinitionNames)); // 示例:修改某个Bean定义的属性 BeanDefinition bd = beanFactory.getBeanDefinition("someBeanName"); MutablePropertyValues pvs = bd.getPropertyValues(); pvs.addPropertyValue("someProperty", "newValue"); } }
2. BeanDefinitionRegistryPostProcessor
这是 BeanFactoryPostProcessor的一个子接口,它提供了一个更早的扩展点,允许开发者动态注册、修改或移除Bean定义。它的执行优先级高于 BeanFactoryPostProcessor。
-
执行时机:同样在
invokeBeanFactoryPostProcessors(beanFactory)中,但会先执行所有BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法。 -
源码示例:
@Component public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 动态注册一个新的Bean定义 RootBeanDefinition beanDefinition = new RootBeanDefinition(MyNewBean.class); registry.registerBeanDefinition("myNewBean", beanDefinition); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 也可以在这里进行BeanFactory的后处理 } }
3. BeanPostProcessor
BeanPostProcessor可能是最常用的扩展点。它允许在Bean实例化、依赖注入完成之后,在初始化方法(如 @PostConstruct、InitializingBean)调用前后,对Bean实例进行额外的处理或包装。
-
执行时机:在Bean生命周期的初始化阶段,具体在
initializeBean方法中。 -
核心方法:
postProcessBeforeInitialization: 在初始化方法之前调用。postProcessAfterInitialization: 在初始化方法之后调用。
-
源码示例:
@Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 在初始化前,可以对bean进行一些处理,例如打印日志 System.out.println("Before initialization of bean: " + beanName); return bean; // 可以返回原始bean或包装后的代理对象 } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // 在初始化后,可以进行其他处理,例如AOP代理 System.out.println("After initialization of bean: " + beanName); return bean; } }典型应用:Spring的AOP(面向切面编程)正是通过
AbstractAutoProxyCreator(它是一个BeanPostProcessor)在postProcessAfterInitialization中为Bean创建代理对象来实现的。
4. 事件监听机制 (ApplicationListener)
Spring提供了基于发布-订阅模型的事件机制,允许容器在发生特定事件(如上下文刷新完成、容器关闭)时,通知注册的监听器。
-
如何工作:
- 自定义事件通常继承
ApplicationEvent。 - 监听器实现
ApplicationListener<E>接口或使用@EventListener注解。 - 通过
ApplicationEventPublisher发布事件。
- 自定义事件通常继承
-
源码示例:
// 1. 定义事件 public class MyCustomEvent extends ApplicationEvent { public MyCustomEvent(Object source) { super(source); } } // 2. 实现监听器 @Component public class MyEventListener implements ApplicationListener<MyCustomEvent> { @Override public void onApplicationEvent(MyCustomEvent event) { System.out.println("Received my custom event: " + event.getSource()); } } // 3. 发布事件 (通常在一个Bean中,该Bean需要实现ApplicationEventPublisherAware来获取发布器) @Component public class MyEventPublisher implements ApplicationEventPublisherAware { private ApplicationEventPublisher publisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; } public void publishEvent() { publisher.publishEvent(new MyCustomEvent(this)); } }
5. FactoryBean
FactoryBean是一个特殊的接口,用于定制复杂对象的创建逻辑。当你向容器获取一个 FactoryBean时,默认得到的是它 getObject()方法返回的对象,而不是 FactoryBean本身。
-
源码示例:
@Component public class MyFactoryBean implements FactoryBean<MyComplexObject> { @Override public MyComplexObject getObject() throws Exception { // 在这里实现复杂的构建逻辑 return new MyComplexObject(); } @Override public Class<?> getObjectType() { return MyComplexObject.class; } @Override public boolean isSingleton() { return true; // 通常返回单例 } }在容器中,通过
&beanName(加上&前缀)可以获取到MyFactoryBean本身,而非它生产的对象。
6. 自动装配与SPI扩展 (spring.factories)
Spring Boot大量使用 META-INF/spring.factories文件来实现约定优于配置的自动装配机制,这类似于Java的SPI(Service Provider Interface)。
-
工作原理:Spring Boot启动时会扫描所有jar包下的
META-INF/spring.factories文件,并根据文件中定义的接口和实现类全名,自动实例化并注册这些Bean。 -
文件示例 (
META-INF/spring.factories):org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.MyAutoConfiguration这告诉Spring Boot自动配置
com.example.MyAutoConfiguration类。
其他重要扩展点
- ImportSelector 与 ImportBeanDefinitionRegistrar: 通常与
@Import注解配合使用,用于动态选择配置类或注册Bean定义。@EnableXXX注解常基于此实现。 - Aware接口族 (如
BeanNameAware,ApplicationContextAware): 让Bean能感知到容器本身或某些特定资源。Spring容器会在Bean生命周期的特定阶段回调这些接口的方法。
总结
Spring的扩展点机制是其设计精髓——开放封闭原则的完美体现。它通过定义清晰的接口和在生命周期关键节点的回调,为开发者提供了巨大的灵活性和控制力,使得集成第三方库和深度定制应用行为变得可能且简单。理解这些扩展点的执行时机和用途,是掌握Spring框架的关键。
本文来自博客园,作者:哈罗·沃德,转载请注明原文链接:https://www.cnblogs.com/panhua/p/19210450
浙公网安备 33010602011771号