Spring--IOC容器
Spring 是一个基于 Java 平台的开源全栈应用步伐框架,也是一个控制反转(IoC)容器实现。
Spring IoC 容器即 Spring 框架中负责管理“Bean”(由容器实例化、配置并组装的普通 POJO 对象)的焦点组件。容器读取配置元数据(XML、注解或 Java 配置类),解析 Bean 界说,然后在启动或按需时实例化 Bean,完成依赖注入,并负责 Bean 的整个生命周期管理。
本文章示例代码见该堆栈:【spring】中的“spring”模块。
堆栈地址:https://gitee.com/quercus-sp204/sourcecode-and-demos
1.相干概念
IOC: Inversion of control 【控制反转】
控制反转是一种设计原则,其焦点思想是:将步伐中对象的创建、配置和生命周期管理的控制权,从应用代码“反转”交给外部框架或容器来负责。在传统的步伐设计中,业务逻辑代码主动调用库或框架完成通用功能;而在 IoC 中,则是框架或容器主动调用开发者编写的代码,实现“控制权”反转,别的呢,IoC 不是一种技术,而是一种思想。
低落组件间的耦合度,提拔体系的可维护性和扩展性。例如,传统开发中Service层直接依赖Dao层的具体实现,而IoC通过容器动态注入依赖,使两者解耦。
DI:Dependency Injection 【依赖注入】
依赖注入是 IoC 最常见的一种实现方式。在 DI 模式下,对象只需声明它所依赖的其他对象(通过构造器、属性或工厂方法),由 IoC 容器在实例化时自动“注入”这些依赖,从而实现组件间的松耦合和可测试性提拔。
在Spring中,我们可以通过构造器注入、Setter方法注入或字段注入(如@Autowired)。- // 构造器注入
- @Component
- public class UserService {
- private final UserDao userDao;
- @Autowired
- public UserService(UserDao userDao) {
- this.userDao = userDao;
- }
- }
复制代码 2.焦点类介绍
我们都知道,spring可以从xml配置文件中解析bean的界说,同时也可以结合相干注解(例如@Configuration, @Bean等)来界说相干bean。最经典的就是这两种了,下面我们就基于这两种类型,来介绍一下相干的焦点类。
①根本的
上面的类间关系图我们必要了解的是赤色框框中的三个,BeanFactory、ApplicationEventPublisher、ApplicationContext。
BeanFactory : IOC容器的焦点接口,界说了基础功能(如getBean()、containsBean()),可以看到,BeanFactory是一个顶级接口,界说了比力常用的getBean方法。- public interface BeanFactory {
- String FACTORY_BEAN_PREFIX = "&";
- Object getBean(String name) throws BeansException;
- <T> T getBean(String name, Class<T> requiredType) throws BeansException;
- <T> T getBean(Class<T> requiredType) throws BeansException;
- boolean containsBean(String name);
- .....
- }
复制代码 ApplicationContext:BeanFactory的扩展接口,提供高级功能(如国际化、事件发布、AOP支持)
用于为应用步伐提供配置的中央接口。这在应用步伐运行时是只读的,但如果实现支持,则可以重新加载。ApplicationContext提供:
继承自 ListableBeanFactory用于访问应用步伐组件的 Bean 工厂方法。
继承自ResourceLoader 接口用以通用方式加载文件资源的能力。
继承自 ApplicationEventPublisher 接口能够将事件发布到已注册的侦听器。
继承自 MessageSource 接口 能够解析消息的能力,支持国际化。- public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
- MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
- .....
- }
复制代码 ApplicationEventPublisher:封装事件发布功能的接口。- @FunctionalInterface
- public interface ApplicationEventPublisher {
- /*
- 向在此应用程序注册过应用程序事件的匹配侦听器 发送通知。
- 事件可以是框架事件(例如 ContextRefreshedEvent)或特定于应用程序的事件。
- 这样的事件发布步骤实际上是移交给 multicaster,并不意味着同步异步执行,甚至根本不意味着立即执行。
- 建议事件侦听器尽可能高效,单独使用异步执行来执行运行时间较长且可能阻塞的作。
- */
- default void publishEvent(ApplicationEvent event) {
- publishEvent((Object) event);
- }
- void publishEvent(Object event); // 接口
- }
复制代码 spring各种类非常多,所以在上图中,我这里只做出了各自类之间的大致关系。
DefaultListableBeanFactory: Spring IoC 容器的 基础实现类,直接管理 Bean 的全生命周期(实例化、依赖注入、销毁);通过BeanDefinitionRegistry 接口注册/移除 Bean 界说(如 XML 或注解配置);preInstantiateSingletons() 方法来实例化bean。-----这个方法是实现了接口ConfigurableListableBeanFactory
AbstractApplicationContext:是 容器启动的模板,扩展了企业级功能并依赖 BeanFactory 实现业务逻辑,通过 refresh() 方法界说容器启动流程(如加载配置、注册 BeanFactoryPostProcessor)。在其子类实现中,重写了obtainFreshBeanFactory()方法,可以获取到beanFactory。
BeanDefinition 接口用于描述一个 Bean 实例的元信息,包罗类名、构造函数参数、属性值、作用域、初始化/销毁方法等。- public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
- .....
- }
复制代码 BeanDefinitionHolder 封装一个 BeanDefinition 以及它对应的 Bean 名称和别名,可用于内部 Bean 的占位或编程式注册时携带额外信息。- public class BeanDefinitionHolder implements BeanMetadataElement {
- private final BeanDefinition beanDefinition;
- private final String beanName;
- @Nullable
- private final String[] aliases;
- ....
- }
复制代码 BeanDefinitionBuilder 用于以流式 API 构造 GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition 等,并设置各种属性(如 scope、lazyInit、autowireMode、initMethod 等)。
②基于注解的context
AnnotationConfigApplicationContext :是 Spring 注解驱动配置的焦点实现。其中的关键组件:
- AnnotatedBeanDefinitionReader
负责解析配置类(@Configuration)并注册 Bean 界说。
焦点逻辑
- 通过 registerBean() 方法将配置类转换为 AnnotatedGenericBeanDefinition。
- 处理 @Bean 方法,生成对应的 Bean 界说。
- 注册 BeanPostProcessor(如 ConfigurationClassPostProcessor)。
- ClassPathBeanDefinitionScanner
扫描包路径下的类,注册组件(@Component、@Service)。
- 过滤条件:默认扫描带有 @Component 及其派生注解的类。
- 扩展点:可通过 includeFilters 和 excludeFilters 自界说过滤规则。
该context初始化流程
- 构造阶段:
- 创建 DefaultListableBeanFactory(底层 BeanFactory)。
- 初始化 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner。
- 注册阶段:
- 解析配置类,生成 BeanDefinition(如 AnnotatedGenericBeanDefinition)。
- 将 Bean 界说注册到 BeanDefinitionRegistry(即 DefaultListableBeanFactory)。
- 刷新阶段(refresh()):
- 预备环境:验证配置属性。
- 获取 BeanFactory:确保 DefaultListableBeanFactory 已初始化。
- 注册 BeanPostProcessor:如 AutowiredAnnotationBeanPostProcessor。
- 完成 Bean 实例化:通过 preInstantiateSingletons() 预加载单例 Bean。
③基于配置文件的context
ClassPathXmlApplicationContext :
- 基于 XML 配置的 Spring 容器:通过加载类路径(ClassPath)下的 XML 文件初始化 Spring 容器,管理 Bean 的生命周期和依赖注入。
- ApplicationContext 的实现类:继承自 AbstractApplicationContext,提供完整的容器功能(如国际化、事件机制)。
- 传统 Spring 应用的焦点入口:实用于 XML 配置驱动的项目(如早期 Spring 项目)。
示例:- <?xml version="1.0" encoding="UTF-8"?>
- <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 scope="singleton" name="policeman">
- <constructor-arg name="name" value="国窖001"/>
- </bean>
- </beans>
复制代码- public class XmlContextMain {
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("all-spring.xml");
- Policeman policeman = context.getBean(Policeman.class);
- policeman.say();
- }
- }
- // 实体类
- public class Policeman {
- private String name;
- public Policeman(){
- System.out.println("Policeman 构造函数");
- }
- public Policeman(String name){
- this.name = name;
- }
- public void say() {
- System.out.println(this.name + "报道!");
- }
- }
复制代码 该示例见spring模块中的带有xml前缀的类和包。
现在ClassPathXmlApplicationContext用的很少了,现代 Spring 开发更倾向注解配置。
3. 容器创建
在了解到了根本的类,以及他们之间的大致关系之后,这本节我们来探索一下IOC容器是如何创建的。那我们就以注解配置的context为例子。- ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
- Husband h = context.getBean(Husband.class);
- h.say();
复制代码 从构造函数一步一步向下走- // AnnotationConfigApplicationContext.java
- public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
- this(); // 1.无参构造
- register(componentClasses); // 2.注册配置类并生成BeanDefinition
- refresh(); // 3.容器刷新
- }
复制代码 ①构造函数
- // 1.无参构造
- public AnnotationConfigApplicationContext() {
- StartupStep createAnnotatedBeanDefReader = getApplicationStartup().start("spring.context.annotated-bean-reader.create");
- // 初始化注解 Bean 定义读取器,通过读取器预注册这些处理器,
- // 以确保后续注解解析和依赖注入的基础能力。
- /*
- 创建 AnnotatedBeanDefinitionReader 实例,负责将
- 注解配置类(如 @Configuration、@Component)转换为 BeanDefinition
- 自动注册关键组件:
- ConfigurationClassPostProcessor(解析 @Configuration 类)。
- AutowiredAnnotationBeanPostProcessor(处理 @Autowired)。
- CommonAnnotationBeanPostProcessor(处理 @Resource、@PostConstruct)。
- EventListenerMethodProcessor(处理 @EventListener)。
- */
- this.reader = new AnnotatedBeanDefinitionReader(this);
- createAnnotatedBeanDefReader.end();
- /*
- 创建 ClassPathBeanDefinitionScanner 实例,负责扫描类路径下的组件类(如 @Component、@Service)
- */
- this.scanner = new ClassPathBeanDefinitionScanner(this);
- }
复制代码 在创建AnnotatedBeanDefinitionReader的时候,默认会创建几个BeanDefinition放到beanDefinitionMap里面。
②注册配置类
[code]// 2.注册配置类并生成BeanDefinition@Overridepublic void register(Class... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); StartupStep registerComponentClass = getApplicationStartup().start("spring.context.component-classes.register") .tag("classes", () -> Arrays.toString(componentClasses)); this.reader.register(componentClasses); registerComponentClass.end();}// AnnotatedBeanDefinitionReader.javapublic void register(Class... componentClasses) { for (Class componentClass : componentClasses) { registerBean(componentClass); }}// 往下末了是调用下面这个private void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class |