你好,我是猿java。
这篇文章,我们将通过剖析 Spring 5.x源码,深度分析 IOC 容器的初始化过程。
1 IOC 的基本概念
IOC,全称Inversion of Control,翻译为,它是一种设计原则,旨在通过减少对象之间的耦合度,提高系统的灵活性和可维护性。在传统的编程方式中,对象通常负责自己依赖的创建和管理,这导致了高耦合度。而在 IOC 模式下,对象的创建和依赖管理交由外部容器控制,实现了对象之间的松耦合。
Spring 的 IOC 容器负责管理应用程序中的对象及其依赖关系。它通过配置元数据(如 XML、注解、Java 配置类等)来描述对象的创建、装配和管理过程。IOC 容器在应用启动时,根据配置元数据创建和装配所有的 Bean,从而实现应用程序的依赖注入。
IOC 容器的核心接口包括:
- BeanFactory :是 Spring IOC 容器的最基本接口,提供了获取 Bean 的基本功能。它延迟加载 Bean,即在第一次调用
getBean
方法时才创建 Bean。 - ApplicationContext:继承自 BeanFactory,提供了更高级的功能,如国际化支持、事件传播、AOP 集成等。ApplicationContext 通常在企业级应用中使用更为广泛。
2. Spring IOC初始化流程
Spring 5.x 在 IOC 容器的初始化过程中,涵盖了配置解析、Bean 定义加载与注册、Bean 的实例化与装配、初始化以及后期处理等多个阶段。以下将对这些阶段进行详细解析。
2.1 配置元数据的解析
在 Spring 应用中,配置元数据描述了应用中各个 Bean 及其依赖关系。配置元数据可以通过多种方式提供,包括 XML 配置文件、注解以及 Java 配置类(基于 @Configuration
的类)。
2.1.1 XML 配置
传统的 Spring 配置方式,通过 XML 文件定义 Bean 及其依赖关系。Spring 通过 XmlBeanDefinitionReader
将 XML 文件解析为 BeanDefinition
对象,并注册到 BeanFactory
中。
示例 XML 配置:
xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBean" class="com.yuanjava.MyBean">
<property name="dependency" ref="myDependency"/>
</bean>
<bean id="myDependency" class="com.yuanjava.MyDependency"/>
</beans>
2.1.2 注解配置
Spring 提供了多种注解,用于定义 Bean 和管理依赖关系,如 @Component
、@Service
、@Repository
、@Controller
、@Configuration
以及 @Autowired
等。通过 ComponentScan
扫描包路径,容器自动检测和注册带有特定注解的类为 Bean。
示例注解配置:
java
@Component
public class MyBean {
@Autowired
private MyDependency myDependency;
}
@Component
public class MyDependency { }
2.1.3 Java 配置
基于 Java 的配置方式,通过 @Configuration
注解的类,使用 @Bean
方法定义 Bean。这种方式结合了类型安全和灵活性,受到越来越多开发者的青睐。
示例 Java 配置:
java
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean(myDependency());
}
@Bean
public MyDependency myDependency() {
return new MyDependency();
}
}
2.2 Bean 定义的加载与注册
配置元数据被解析后,Spring IOC 容器需要将其转化为内部的 BeanDefinition
对象,并注册到 BeanFactory
中。BeanDefinition
包含了 Bean 的类名、作用域、初始化方法、销毁方法、依赖关系等信息。
在 Spring 5.x 中,具体步骤通常如下:
- 创建
BeanFactory
实例 :常用的实现类是DefaultListableBeanFactory
。 - 使用
BeanDefinitionReader
读取配置 :如XmlBeanDefinitionReader
、AnnotatedBeanDefinitionReader
、ConfigurationClassPostProcessor
等。 - 解析并注册
BeanDefinition
:将解析后的 Bean 定义注册到 BeanFactory 中。
示例代码:
java
// 创建 BeanFactory 实例
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建 BeanDefinitionReader
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// 加载 XML 配置文件
reader.loadBeanDefinitions("classpath:applicationContext.xml");
// 或者使用注解配置
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
2.3 Bean 的实例化与装配
在 Bean 定义加载并注册后,IOC 容器根据需要实例化 Bean,并完成属性的注入与依赖的装配。Spring 提供了多种方式来完成 Bean 的实例化与装配,如构造函数注入、Setter 方法注入、注解注入等。
2.3.1 实例化策略
Spring 提供了多种 Bean 的实例化策略,包括:
- 通过无参构造函数实例化:默认的实例化方式。
- 通过工厂方法实例化:可以通过静态工厂方法或实例工厂方法来创建 Bean。
- 通过构造函数参数实例化:支持通过构造函数参数传递依赖。
2.3.2 依赖注入方式
依赖注入分为两种主要方式:
-
构造函数注入:通过构造函数传递依赖对象。
javapublic class MyBean { private final MyDependency myDependency; public MyBean(MyDependency myDependency) { this.myDependency = myDependency; } }
-
Setter 方法注入:通过 Setter 方法注入依赖对象。
java
public class MyBean {
private MyDependency myDependency;
@Autowired
public void setMyDependency(MyDependency myDependency) {
this.myDependency = myDependency;
}
}
在 Spring 5.x 中,推荐使用构造函数注入,因为它更符合不可变对象的设计理念,且有利于编写可测试的代码。
2.3.3 自动装配
Spring 支持自动装配,减少了显式配置的工作量。自动装配有以下几种模式:
- 按类型自动装配 (
@Autowired
):根据 Bean 的类型进行装配。 - 按名称自动装配 (
@Qualifier
) :结合@Qualifier
注解指定 Bean 的名称。 - 基于 Java 注解的装配 :如
@Primary
、@Resource
等。 - 基于构造函数的自动装配:通过构造函数参数进行装配。
示例代码:
java
@Component
public class MyService {
private final MyRepository myRepository;
@Autowired
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
2.4 Bean 的初始化
在 Bean 被实例化并装配完成后,还需要进行初始化工作。初始化过程包括执行自定义的初始化方法、BeanPostProcessor
的前置和后置处理等。
2.4.1 InitializingBean 接口
Bean 可以通过实现 InitializingBean
接口,重写 afterPropertiesSet
方法来自定义初始化逻辑。
java
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
}
}
2.4.2 自定义初始化方法
在 Bean 配置中,可以通过 init-method
属性指定自定义的初始化方法。
xml
<bean id="myBean" class="com.yuanjava.MyBean" init-method="init"/>
或者通过注解 @PostConstruct
指定初始化方法:
java
public class MyBean {
@PostConstruct
public void init() {
// 初始化逻辑
}
}
2.4.3 BeanPostProcessor
BeanPostProcessor
是 Spring 提供的扩展点,允许在 Bean 初始化前后进行自定义处理。常见的实现类有 AutowiredAnnotationBeanPostProcessor
、CommonAnnotationBeanPostProcessor
、ProxyPostProcessor
等。
BeanPostProcessor
提供两个主要方法:
- postProcessBeforeInitialization:在 Bean 初始化方法调用前执行。
- postProcessAfterInitialization:在 Bean 初始化方法调用后执行。
示例代码:
java
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 初始化前处理
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 初始化后处理
return bean;
}
}
2.5 Bean 的后处理与销毁
Bean 的生命周期不仅包括初始化,还包括销毁过程。Spring 提供了多种机制来处理 Bean 的销毁,如实现 DisposableBean
接口、指定销毁方法、使用 @PreDestroy
注解等。
2.5.1 DisposableBean 接口
通过实现 DisposableBean
接口,Bean 可以在销毁前执行特定的逻辑。
java
public class MyBean implements DisposableBean {
@Override
public void destroy() throws Exception {
// 销毁逻辑
}
}
2.5.2 自定义销毁方法
在 Bean 配置中,可以通过 destroy-method
属性指定自定义的销毁方法。
xml
<bean id="myBean" class="com.yuanjava.MyBean" destroy-method="cleanup"/>
或者使用 @PreDestroy
注解指定销毁方法:
java
public class MyBean {
@PreDestroy
public void cleanup() {
// 销毁逻辑
}
}
2.5.3 DisposableBean 与 destroy-method 的优先级
当 Bean 同时实现了 DisposableBean
接口并指定了 destroy-method
时,Spring 会按照以下顺序执行销毁逻辑:
- 执行实现的
DisposableBean
接口的destroy
方法。 - 执行
destroy-method
指定的方法。
这种方法确保了销毁逻辑的有序执行,且用户可以通过合理配置完成自定义的销毁操作。
3. 关键类与组件
在 Spring 5.x 中,IOC 容器的初始化过程涉及到多个关键类和组件,这些类和组件各司其职,共同完成容器的初始化与管理工作。以下将介绍其中几个重要的类和组件。
3.1 ApplicationContext 接口及其实现
ApplicationContext 是 Spring IOC 容器的核心接口,继承自 BeanFactory,提供了更强大的功能。常见的实现类包括:
- ClassPathXmlApplicationContext:基于类路径的 XML 配置文件创建 ApplicationContext。
- FileSystemXmlApplicationContext:基于文件系统的 XML 配置文件创建 ApplicationContext。
- AnnotationConfigApplicationContext:基于 Java 注解的配置类创建 ApplicationContext。
- GenericWebApplicationContext:适用于 Web 应用的泛化 ApplicationContext。
示例代码:
java
// 基于 XML 配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 基于注解配置
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
3.2 DefaultListableBeanFactory
DefaultListableBeanFactory 是 BeanFactory
的默认实现,也是最常用的实现类之一。它支持 Bean 的定义注册、依赖注入、Bean 后处理、作用域管理等功能。
java
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
3.3 BeanDefinition 与 BeanDefinitionReader
BeanDefinition 是 Spring 内部用于描述 Bean 的核心类,包含了 Bean 的类名、作用域、依赖关系、初始化方法等信息。
BeanDefinitionReader 是用于读取不同格式的配置元数据并注册到 BeanFactory 中的接口,常见的实现类有:
- XmlBeanDefinitionReader:读取 XML 配置文件。
- AnnotatedBeanDefinitionReader:读取基于注解的配置。
- PropertiesBeanDefinitionReader:读取基于 properties 文件的配置。
示例代码:
java
// 创建 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 创建 XML BeanDefinitionReader
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// 加载 XML 配置
reader.loadBeanDefinitions("classpath:applicationContext.xml");
3.4 InstantiationStrategy
InstantiationStrategy 接口定义了 Bean 实例化的策略。Spring 提供了两种默认的实现:
- SimpleInstantiationStrategy:简单的实例化策略,适用于多数场景。
- CglibSubclassingInstantiationStrategy:使用 CGLIB 生成子类进行实例化,常用于需要 AOP 代理的 Bean。
java
InstantiationStrategy strategy = new SimpleInstantiationStrategy();
3.5 AutowireCapableBeanFactory
AutowireCapableBeanFactory 是 BeanFactory 的子接口,提供了更高级别的功能,如支持自动装配、Bean 后处理等。它在 Spring 的自动装配和后处理机制中起到了关键作用。
java
AutowireCapableBeanFactory autowireCapableBeanFactory = context.getAutowireCapableBeanFactory();
3.6 BeanPostProcessor
BeanPostProcessor 是 Spring 提供的扩展点,用于在 Bean 的初始化前后进行自定义处理。常用的实现类包括:
- AutowiredAnnotationBeanPostProcessor :处理
@Autowired
注解的装配。 - CommonAnnotationBeanPostProcessor :处理
@PostConstruct
和@PreDestroy
注解。 - ProxyPostProcessor:用于生成 AOP 代理等。
java
public class MyCustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 自定义前置处理
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 自定义后置处理
return bean;
}
}
4. 总结
本文,我们通过源码深度分析了 Spring 5.x IOC容器的启动流程,IOC是 Spring的核心,也是比较难懂的一部分,建议可以多去阅读 Spring源码,了解其精髓。
5. 学习交流
如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。