Skip to content

Latest commit

 

History

History
3189 lines (2516 loc) · 110 KB

2024-02-01-IoC.md

File metadata and controls

3189 lines (2516 loc) · 110 KB
layout title date categories tags series series_index comments copyrights
post
IoC
2024-02-01 00:00:00 +0800
编程
java spring
深入 Spring 源码
1
true
原创

Spring 是一个开源的轻量级 JavaEE 框架。它的核心是控制反转(IoC)和面向切面编程(AOP)。Spring 的 IoC 容器负责管理 JavaBean 的生命周期,而 AOP 容器负责管理切面。Spring 还提供了一系列的模块,如 Spring MVC、Spring JDBC、Spring Security 等。

Spring

Spring 架构图

这张图有点老旧了,还是 4.x 版本的,不过总体上还是没什么变化。

总体上来讲,Spring 分为以下几个部分:

  • 核心技术(Core Technologies)

    • IoC Container:负责管理 JavaBean 的生命周期
    • Resources:资源管理
    • Validation, Data binding, Type conversion:数据验证、数据绑定、类型转换
    • SpEL:Spring 表达式语言
    • AOP:面向切面编程
  • 数据访问(Data Access)

    • Transactions:事务管理
    • DAO support:数据访问支持
    • JDBC:JDBC 支持
    • ORM:对象关系映射支持
  • Web

    • Servlet

      • Web MVC
      • REST
      • WebSocket
    • Web Reactive

      • WebFlux
      • WebClient
      • WebSocket
  • Testing

  • Integration

除此之外,Spring 拥有非常丰富的生态系统,例如:

  • Spring Boot:简化 Spring 的配置和使用
  • Spring Cloud:微服务架构
  • Spring Security:安全框架

等等。

IoC

为什么需要 IoC

在实际开发中,常常会用到三层架构。

点击查看三层架构基础

三层架构是一种软件开发的设计模式,它将应用程序分为三个主要层次:

  • 控制器层(Controller):负责与用户进行交互,展示数据,并接收用户输入。例如网页前端、移动应用的用户界面等。
  • 业务逻辑层(Service):处理应用程序的核心功能和业务规则。例如应用程序的中间层代码,包含处理用户请求、验证输入、执行算法等逻辑。
  • 持久层(Dao):负责与数据库或其他数据存储系统进行交互。例如数据访问对象,负责执行数据库查询、插入、更新和删除操作的代码。

假设我们在开发一个网上书店系统,可以将系统划分为以下三个层次:

  • 控制器层:负责显示商品列表、搜索结果、商品详情页等。

    public class BookControllerImpl implements BookController {
        private BookService bookService = new BookServiceImpl();
    
        public void listBooks() {
            List<Book> books = bookService.listBooks();
            
            for (Book book : books) {
                System.out.println(book);
            }
        }
    }
  • 业务逻辑层:处理用户搜索商品、添加商品到购物车、下单等操作。

    public class BookServiceImpl implements BookService {
        private BookDao bookDao = new BookDaoImpl();
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }
  • 持久层:与数据库交互,查询商品信息、保存订单信息等。

    public class BookDaoImpl implements BookDao {
        public List<Book> listBooks() {
            // 查询数据库,返回商品列表
            return new ArrayList<>();
        }
    }

在逻辑上,这三层应该是一个倒金字塔型:大量控制器层调用少量业务逻辑层,持久层最少:

倒金字塔型

这样的简单写法有几个问题:

  • 资源浪费

    在实际实现中,由于每个 BookControllerImpl 都使用 new 创建了新的 BookServiceImpl 实例、每个 BookServiceImpl 都使用 new 创建了新的 BookDaoImpl 实例,导致了每个控制器层组件都挂了一个金字塔型的结构:

    金字塔型

    这造成了极大的浪费——因为我们知道,BookDaoImpl 很可能只需要一个实例就够用,而不是每个 BookServiceImpl 都创建一个实例。

  • 耦合度高

    由于每个层次都直接依赖于下一层次,导致了耦合度过高。假如 BookDaoImpl 需要更换为 BookDaoAnotherImpl,那么每一个原来依赖于 BookDaoImpl 的类都需要进行修改。

  • 初始化和配置麻烦

    由于每个层次都需要手动创建下一层次的实例,导致了初始化和配置的麻烦。例如配置一个 JDBC 需要:

    dataSource = new DataSource();
    dataSource.setUrl("jdbc:mysql://localhost:3306/bookstore");
    dataSource.setUsername("root");
    dataSource.setPassword("password");
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");

    目前的方法下,每个 BookDaoImpl 都需要写这么长一串,而且如果数据库地址、用户名、密码等信息发生变化,每个 BookDaoImpl 都需要修改。

  • 测试困难

    由于每个层次都直接依赖于下一层次,导致了测试困难。例如,如果要测试 BookControllerImpl,就需要让 BookServiceImplBookDaoImpl 也参与测试。

    这样的测试方式不仅耗时,而且会导致测试结果不稳定。因为 BookServiceImplBookDaoImpl 的实现可能会影响 BookControllerImpl 的测试结果。

至此,IoC 的想法已经呼之欲出了:将对象的创建、配置和管理交给容器,使其与对象的使用解耦。

  • 对于资源浪费的问题,IoC 容器默认使用单例模式,保证只有一个实例
  • 对于耦合度高的问题,当需要更换实现类时,名称可以保持不变,只需要修改配置文件中对应的实现类即可
  • 对于初始化和配置麻烦的问题,只需要在配置文件中配置一次,容器会自动读取配置文件并创建对象
  • 对于测试困难的问题,只需要将测试对象注入到容器中,容器会自动创建依赖的对象

这让我想到了前端常用的状态管理库,例如 Redux 和 Pinia 等。这些库的核心思想也是如此:将对象的创建、配置和管理交给库,使其与对象的使用解耦。

IoC 容器

Spring 的 IoC 容器是一个对象工厂,负责创建、配置和管理对象。在 IoC 容器中,对象被称为 Bean。

我们回顾一下工厂模式。

工厂模式是一种创建对象的设计模式,它提供了一个创建对象的接口,而不需要指定具体的类。

在 IoC 中,产品就是具体的类(或者说是 Bean),工厂就是 IoC 容器。客户端只需要向 IoC 容器请求某个类型的 Bean,而不需要指定具体的类。Bean 的生产和管理都交给 IoC 容器负责,客户端只需要关心 Bean 的使用。

Spring 提供了两种 IoC 容器:BeanFactoryApplicationContext。其中:

  • BeanFactory 是 Spring 的基础容器,如果没有特殊需求一般不用
  • ApplicationContextBeanFactory 的子接口,提供了更多的功能,一般使用 ApplicationContext

例如,我们有一个 Book 类:

package com.example;

public class Book {
    private String title;
    private String author;

    public Book() {
    }

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "title='" + title + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

在未使用 IoC 容器时,我们需要手动创建 Book 对象:

package com.example;

public class TestBook {
    @Test
    public void testBook() {
        Book book = new Book("Spring", "Rod Johnson");
        System.out.println(book);
    }
}

使用 IoC 容器后,我们则需要完成以下步骤:

  • 创建一个配置文件。例如叫 Beans.xml,配置 Book 类:

    <?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 id="book" class="com.example.Book">
            <property name="title" value="Spring"/>
            <property name="author" value="Rod Johnson"/>
        </bean>
    
    </beans>

    这会将类和对应的属性都配置在 XML 文件中,形成一个 Bean 定义。

  • 创建一个 ApplicationContext 对象,并从配置文件中读取 book 对象:

    package com.example;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestBook {
        @Test
        public void testBook() {
            ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            Book book = (Book) context.getBean("book");
            System.out.println(book);
        }
    }

    我们在 JVM 中讨论过类加载器的概念。

    这里,我们相当于使用了当前线程的上下文类加载器,它会从 classpath 中加载 Beans.xml 文件。

    在加载后,会完成 IoC 容器的完整初始化过程。

这样,我们就使用 IoC 容器创建了 Book 对象。

依赖注入

依赖注入(Dependency Injection,DI)是一种设计模式,被用于实现控制反转

它通过将对象的依赖关系从代码中移除,转而由外部容器(如 Spring)在运行时注入。它主要有三种方式:

  • 构造器注入
  • setter 方法注入
  • 字段注入(不推荐,因为破坏了封装性)

具体来讲,在 XML 配置中,这样使用:

构造器注入

构造器注入是通过构造器来注入依赖的。上面的例子中我们定义了有参构造函数 Book(String title, String author),可以通过 constructor-arg 元素来注入依赖:

<bean id="book" class="com.example.Book">
    <constructor-arg name="title" value="Spring"/>
    <constructor-arg name="author" value="Rod Johnson"/>
</bean>

Spring 会自动调用 Book 类的有参构造函数,将 titleauthor 参数传入。

setter 方法注入

setter 方法注入是通过 setter 方法来注入依赖的。例如,在上一节的例子中,我们通过 property 元素来注入 titleauthor 字段:

<bean id="book" class="com.example.Book">
    <property name="title" value="Spring"/>
    <property name="author" value="Rod Johnson"/>
</bean>

Spring 会自动调用 Book 类的 setTitlesetAuthor 方法,将 titleauthor 字段注入到 Book 对象中。

字段注入

字段注入是通过字段的 setter 方法来注入依赖的。例如,在上一节的例子中,我们通过 property 元素来注入 titleauthor vv:

<bean id="book" class="com.example.Book">
    <property name="title" value="Spring"/>
    <property name="author" value="Rod Johnson"/>
</bean>

Spring 会自动调用 Book 类的 setTitlesetAuthor 方法,将 titleauthor 属性注入到 Book 对象中。

特殊值的注入

这当中有一些细节需要注意:

  • 特殊值注入

    • 如果需要注入 null,可以使用 <null/> 元素:

      <property name="title">
          <null/>
      </property>
    • 如果字符串中包含特殊字符,可以使用 <![CDATA[]]> 来包裹:

      <property name="title">
          <value><![CDATA[Spring & Hibernate]]></value>
      </property>

      也可以使用 HTML 转义字符:

      <property name="title">
          <value>Spring &amp; Hibernate</value>
      </property>
  • 引用注入

    如果需要注入另一个 Bean,可以使用 ref 属性:

    <bean id="author" class="com.example.Author">
        <property name="name" value="Rod Johnson"/>
    </bean>
    
    <bean id="book" class="com.example.Book">
        <property name="title" value="Spring"/>
        <property name="author" ref="author"/>
    </bean>  

    这也可以写成:

    <bean id="book" class="com.example.Book">
        <property name="title" value="Spring"/>
        <property name="author">
            <ref bean="author"/>
        </property>
    </bean>

    当然,也可以直接写在内部:

    <bean id="book" class="com.example.Book">
        <property name="title" value="Spring"/>
        <property name="author">
            <bean class="com.example.Author">
                <property name="name" value="Rod Johnson"/>
            </bean>
        </property>
    </bean>
  • 集合注入

    如果需要注入集合,可以使用 listsetmapprops 等元素:

    <bean id="book" class="com.example.Book">
        <property name="authors">
            <list>
                <value>Rod Johnson</value>
                <value>Juergen Hoeller</value>
                <value>Keith Donald</value>
            </list>
        </property>
    </bean>
    <bean id="book" class="com.example.Book">
        <property name="authors">
            <set>
                <value>Rod Johnson</value>
                <value>Juergen Hoeller</value>
                <value>Keith Donald</value>
            </set>
        </property>
    </bean>
    <bean id="book" class="com.example.Book">
        <property name="authors">
            <map>
                <entry key="Rod Johnson" value="Spring"/>
                <entry key="Juergen Hoeller" value="Spring Boot"/>
                <entry key="Keith Donald" value="Spring Cloud"/>
            </map>
        </property>
    </bean>
    <bean id="book" class="com.example.Book">
        <property name="authors">
            <props>
                <prop key="Rod Johnson">Spring</prop>
                <prop key="Juergen Hoeller">Spring Boot</prop>
                <prop key="Keith Donald">Spring Cloud</prop>
            </props>
        </property>
    </bean>
  • p 命名空间

    Spring 提供了 p 命名空间,可以简化属性注入。

    首先需要在配置文件中引入 p 命名空间:

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    然后可以使用 p 命名空间来注入属性:

    <bean id="book" class="com.example.Book" p:title="Spring" p:author="Rod Johnson"/>

    这等价于:

    <bean id="book" class="com.example.Book">
        <property name="title" value="Spring"/>
        <property name="author" value="Rod Johnson"/>
    </bean>

    对于使用 ref 属性的情况,也可以使用 p 命名空间:

    <bean id="book" class="com.example.Book" p:title="Spring" p:author-ref="author"/>

自动装配

自动装配(Autowiring)是 Spring 对 DI 的一种实现方式。它可以自动识别 Bean 之间的依赖关系,从而省去了手动配置 Bean 之间的依赖关系。

Spring 提供了以下几种自动装配的方式:

  • no

    默认值,不自动装配。需要手动配置 Bean 之间的依赖关系。

  • byName

    根据 Bean 的名称自动装配。Spring 会自动查找与属性名相同的 Bean,并将其注入。例如:

    <bean id="author" class="com.example.Author">
        <property name="name" value="Rod Johnson"/>
    </bean>
    
    <bean id="book" class="com.example.Book">
        <property name="author" ref="author"/>
        <property name="title" value="Spring"/>
    </bean>

    最后一条可以被写为:

    <bean id="book" class="com.example.Book" autowire="byName">
        <property name="title" value="Spring"/>
    </bean>

    可以看到,authorBook 的属性名相同,Spring 会自动查找 author Bean,并将其注入到 Book 对象中。

  • byType

    根据 Bean 的类型自动装配。Spring 会自动查找与字段类型相同的 Bean,并将其注入。

    同样的,最后一条可以被写为:

    <bean id="book" class="com.example.Book" autowire="byType">
        <property name="title" value="Spring"/>
    </bean>

    如果有多个 Bean 的类型相同,Spring 会抛出异常。可以使用 @Primary 注解来指定首选 Bean。

  • constructor

    根据构造器参数类型自动装配。Spring 会自动查找与构造器参数类型相同的 Bean,并将其注入。

    例如,Book 类有一个构造器 Book(Author author, String title),可以写为:

    <bean id="book" class="com.example.Book" autowire="constructor">
        <constructor-arg value="Spring"/>
    </bean>

    Spring 会自动查找 Author 类型的 Bean,并将其注入到 Book 对象中。

基于注解的配置

以上我们都在使用 XML 文件来配置 Bean,Spring 也支持使用注解来配置 Bean。

假设我们有两个实现类 BookServiceImplBookDaoImpl

public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();

    public List<Book> listBooks() {
        return bookDao.listBooks();
    }
}
public class BookDaoImpl implements BookDao {
    public List<Book> listBooks() {
        // 查询数据库,返回商品列表
        return new ArrayList<>();
    }
}

其中,BookServiceImpl 依赖于 BookDaoImpl

启用注解扫描

为了实现 IoC,首先需要启用注解扫描。这有两种方法:

  • XML 文件

    在 XML 文件中添加以下配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context"
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
      
          <context:component-scan base-package="com.example"/>
    
    </beans>

    其中 base-package 属性指定了要扫描的包。

  • Java 配置类

    也可以使用 Java 配置类来启用注解扫描:

    以上我们依然用到了部分 XML 配置,Spring 也提供了完全基于注解的配置。例如,我们可以使用 @Configuration 注解来标记配置类:

    @Configuration
    @ComponentScan(basePackages = "com.example")
    public class AppConfig {
    }

    其中,@Configuration 注解标记了一个配置类,@ComponentScan 注解启用了注解扫描。

    此时,使用时不再需要加载 XML 文件,而是直接加载配置类:

    public class TestBook {
        @Test
        public void testBook() {
            ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            Book book = context.getBean(Book.class);
            System.out.println(book);
        }
    }

    这样,我们就完全使用注解来配置 Bean 了。

注册 Bean

然后可以使用注解,注册为 Bean:

@Service
public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();

    public List<Book> listBooks() {
        return bookDao.listBooks();
    }
}
@Repository
public class BookDaoImpl implements BookDao {
    public List<Book> listBooks() {
        // 查询数据库,返回商品列表
        return new ArrayList<>();
    }
}

这里有两个需要说明的地方:

  • @Component 注解是 Spring 的通用注解,可以用于任何类。Spring 还提供了一些更具体的注解,如
    • @Repository:持久层
    • @Service:业务逻辑层
    • @Controller:控制器层
  • 生成的 Bean 的名称默认为类名的首字母小写,可以使用 @Component(value = "book") 来指定 Bean 的名称

当然,你也可以直接将 Bean 类写进配置类中:

@Configuration
public class AppConfig {
    @Bean
    public BookService bookService() {
        return new BookServiceImpl();
    }

    @Bean
    public BookDao bookDao() {
        return new BookDaoImpl();
    }
}

它们需要使用 @Bean 注解来标记这是一个 Bean。

属性注入

注册类为 Bean 后,就可以向其中注入属性了。

如果注入的是另一个 Bean,可以使用 @Autowired 注解。例如,要想将 BookDaoImpl 注入到 BookServiceImpl 中,有这样几种方法:

  • 构造器注入

    @Service
    public class BookServiceImpl implements BookService {
        private BookDao bookDao;
    
        @Autowired
        public BookServiceImpl(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }

    如果写在形参上也是可以的:

    @Service
    public class BookServiceImpl implements BookService {
        private BookDao bookDao;
    
        public BookServiceImpl(@Autowired BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }

    如果只有一个构造器,@Autowired 可以省略。

    • setter 方法注入
    @Service
    public class BookServiceImpl implements BookService {
        private BookDao bookDao;
    
        @Autowired
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }
  • 字段注入

    @Service
    public class BookServiceImpl implements BookService {
        @Autowired
        private BookDao bookDao;
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }

这里有两个比较特殊的:

  • @Qualifier 注解注入

    @Autowired 默认按类型注入,如果有多个 Bean 的类型相同(例如 BookDao 接口有多个实现),可以使用 @Qualifier 注解来指定 Bean 的名称:

    @Service
    public class BookServiceImpl implements BookService {
        @Autowired
        @Qualifier("bookDaoImpl")
        private BookDao bookDao;
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }

    这里的 bookDaoImplBookDaoImpl 类的 Bean 名称。

  • @Resource 注解注入

    @Autowired 不同,@Resource 注解是 JDK 扩展包中的,它默认按名称注入,如果找不到名称则按照类型注入。它只能被用在字段或者 setter 方法上:

    @Service
    public class BookServiceImpl implements BookService {
        @Resource(name = "bookDaoImpl")
        private BookDao bookDao;
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }

    这里的 bookDaoImplBookDaoImpl 类的 Bean 名称。

对于非 Bean 的字段(例如基本类型、String 类型等),可以使用 @Value 注解注入:

  • @Value 注解注入

    @Value 注解可以用来注入基本类型、String 类型、数组、集合等。例如:

    @Component
    public class Book {
        @Value("Spring")
        private String title;
    
        @Value("Rod Johnson")
        private String author;
    
        @Value("${book.price}")
        private double price;
    
        @Value("${book.authors}")
        private String[] authors;
    
        @Value("#{${book.authors}}")
        private List<String> authorsList;
    }

    这里有几个需要注意的地方:

    • 如果需要注入的是一个基本类型,可以直接写在 @Value 注解中
    • 如果需要注入的是一个 SpEL 表达式,可以使用 #{} 包裹,它会在运行时计算表达式的值,通常用于数组、集合等
    • 如果需要注入的是一个外部配置文件中的值,可以使用 ${} 包裹,它会在运行时读取配置文件中的值

生命周期

Bean 的生命周期是指 Bean 从创建到销毁的过程。Spring 提供了多种方式来管理 Bean 的生命周期。

Spring 找到、创建、管理和销毁一个 Bean 的大致流程为:

  1. 扫描包,获取所有资源
  2. 解析资源,获取 BeanDefinition
  3. 管理 Bean 的生命周期
    1. 实例化
    2. 填充属性
    3. 初始化
    • @PostConstruct
    • InitializingBean.afterPropertiesSet()
    • @Bean(initMethod = "init")
    1. 自由使用
    2. 销毁
    • @PreDestroy
    • DisposableBean.destroy()
    • @Bean(destroyMethod = "destroy")

之所以显得如此复杂,是因为它要考虑到很多问题,比如:

  • BeanFactory 和 ApplicationContext 的区别
  • XML 和注解两种配置方式
  • Bean 的作用域
  • 多种依赖注入方式
  • BeanPostProcessor
  • 父子容器

其中,很多东西(比如 BeanFactory)根本没什么人用,纯纯的历史包袱,目前已经被标记为弃用了。

初始化方法

  • 可以使用 @PostConstruct 注解来标记初始化方法:

    @Service
    public class BookServiceImpl implements BookService {
        @PostConstruct
        public void init() {
            System.out.println("BookServiceImpl initialized");
        }
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }
  • 如果是定义在配置类中的 Bean,可以使用 @Bean(initMethod = "init") 来指定初始化方法:

    @Configuration
    public class AppConfig {
        @Bean(initMethod = "init")
        public BookService bookService() {
            return new BookServiceImpl();
        }
    }
  • 实现 InitializingBean.afterPropertiesSet() 方法也可以用来标记初始化方法:

    @Service
    public class BookServiceImpl implements BookService, InitializingBean {
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("BookServiceImpl initialized");
        }
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }

销毁方法

  • 可以使用 @PreDestroy 注解来标记销毁方法:

    @Service
    public class BookServiceImpl implements BookService {
        @PreDestroy
        public void destroy() {
            System.out.println("BookServiceImpl destroyed");
        }
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }
  • 如果是定义在配置类中的 Bean,可以使用 @Bean(destroyMethod = "destroy") 来指定销毁方法:

    @Configuration
    public class AppConfig {
        @Bean(destroyMethod = "destroy")
        public BookService bookService() {
            return new BookServiceImpl();
        }
    }
  • 实现 DisposableBean.destroy() 方法也可以用来标记销毁方法:

    @Service
    public class BookServiceImpl implements BookService, DisposableBean {
        @Override
        public void destroy() throws Exception {
            System.out.println("BookServiceImpl destroyed");
        }
    
        public List<Book> listBooks() {
            return bookDao.listBooks();
        }
    }

PostProcessor

BeanPostProcessor 是 Spring 提供的一个接口,可以用来在 Bean 初始化前后执行一些操作。它有两个方法:

  • postProcessBeforeInitialization(Object bean, String beanName):在 Bean 初始化前执行
  • postProcessAfterInitialization(Object bean, String beanName):在 Bean 初始化后执行

例如,我们可以实现一个 BeanPostProcessor,在 Bean 初始化前后打印日志:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Before initialization: " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("After initialization: " + beanName);
        return bean;
    }
}

这个东西会在下一篇 AOP 中用到,现在先不管。

其它问题

循环依赖

此外,我们还看到了处理循环依赖的方法。Spring 解决了单例模式下,setter 注入的循环依赖问题。解决的方式是通过三级缓存:

  • 创建 A
    • 实例化 A:调用 A 的构造方法,生成一个原始对象(未注入属性)
    • 将A的工厂放入三级缓存:将生成A原始对象的 ObjectFactory 存入三级缓存(singletonFactories
    • 填充属性 B:发现 A 依赖 B,尝试从缓存获取 B,但 B 未创建,触发创建 B
  • 创建 B
    • 实例化 B:生成 B 的原始对象
    • 将 B 的工厂放入三级缓存
    • 填充属性 A:发现 B 依赖 A,尝试从缓存获取 A:
      • 从三级缓存中找到 A 的 ObjectFactory,调用其 getObject() 方法获取 A 的早期引用(可能经过 AOP 代理)
      • 将 A 的早期引用放入二级缓存(earlySingletonObjects),并清理三级缓存中的 A 工厂
  • 完成 B 的初始化
    • 属性填充完成:B 中的 A 属性已被注入(早期引用)
    • 执行初始化逻辑(如 @PostConstruct
    • 将 B 放入一级缓存:B 成为完整 Bean,存入 singletonObjects
  • 完成 A 的初始化
    • 注入 B 的完整实例:此时 B 已在一级缓存中,A 的 B 属性被注入
    • 执行初始化逻辑
    • 将 A 从二级缓存移除,存入一级缓存

可以看到,解决的前提是已经实例化。这就是为什么 Spring 只解决 setter 注入的循环依赖,而不解决构造函数注入的循环依赖。

作用域

Spring 提供了多种作用域来管理 Bean 的生命周期:

  • singleton:单例模式,默认值。Spring 容器只会创建一个 Bean 实例,并在整个应用程序中共享。
  • prototype:原型模式。每次从容器中获取 Bean 时,都会创建一个新的 Bean 实例。
  • request:请求作用域。每次 HTTP 请求都会创建一个新的 Bean 实例。仅在 Web 应用程序中有效。
  • session:会话作用域。每个 HTTP 会话都会创建一个新的 Bean 实例。仅在 Web 应用程序中有效。
  • globalSession:全局会话作用域。每个全局 HTTP 会话都会创建一个新的 Bean 实例。仅在 Web 应用程序中有效。

可以使用 @Scope 注解来指定 Bean 的作用域:

@Service
@Scope("prototype")
public class BookServiceImpl implements BookService {
    public List<Book> listBooks() {
        return bookDao.listBooks();
    }
}

通常来讲,只会用到 singleton 这一种。

IoC 源码解读

IoC 关键类

IoC 最核心的思想包括了以下两点:

  • 控制反转:将对象的创建和管理交给 Spring 容器,而不是由其它对象来管理。Spring 容器会在特定的生命周期事件(如初始化、销毁)发生时,自动调用对象的相应方法
  • 依赖查找 & 依赖注入:通过依赖查找来获取对象的引用,通过依赖注入来将对象注入到其它对象中,而不是由对象自身来获取它的依赖

方便起见,我们只看注解配置的 IoC 容器。

源码我们从 AnnotationConfigApplicationContext 开始。我们最常用的构造函数是 AnnotationConfigApplicationContext(String... basePackages)

public AnnotationConfigApplicationContext(String... basePackages) {
    this();
    scan(basePackages);
    refresh();
}

它一共分了三步:

构造方法

点击查看构造方法源码解读

this() 当然是先调用 AnnotationConfigApplicationContext() 构造函数:

public AnnotationConfigApplicationContext() {
    StartupStep createAnnotatedBeanDefReader = getApplicationStartup().start("spring.context.annotated-bean-reader.create");
    // 注解 Bean 读取器
    this.reader = new AnnotatedBeanDefinitionReader(this);
    createAnnotatedBeanDefReader.end();
    // 注解 Bean 扫描器
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

同时还会调用父类 GenericApplicationContext 的构造函数:

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

它会创建一个 DefaultListableBeanFactory 对象:

public DefaultListableBeanFactory() {
    super();
}

这个对象就是默认情况下,用来创建 Bean 的工厂类。

我们看到这玩意儿直接调用了 AbstractAutowireCapableBeanFactory 的构造函数:

public AbstractAutowireCapableBeanFactory() {
    super();
    // 忽略 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 等接口(下文会详细介绍)
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
    // 使用 CGLIB 代理
    this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
}

BeanNameAware、BeanFactoryAware 和 BeanClassLoaderAware 是 Spring 框架中的三个回调接口,允许 Bean 在初始化阶段获取与容器相关的信息。

  • BeanNameAware:获取 Bean 的名称

    可以通过实现这个接口的 setBeanName() 方法来获取 Bean 的名称

    public class MyBean implements BeanNameAware {
        private String beanName;
    
        @Override
        public void setBeanName(String name) {
            this.beanName = name;
        }
    }
  • BeanFactoryAware:获取 BeanFactory

    可以通过实现这个接口的 setBeanFactory() 方法来获取 BeanFactory。这可以帮助我们动态地获取 BeanFactory 中的其他 Bean 或者执行一些与容器相关的操作

    public class MyBean implements BeanFactoryAware {
        private BeanFactory beanFactory;
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }
    
        public void doSomething() {
            MyOtherBean otherBean = beanFactory.getBean(MyOtherBean.class);
            // 使用 otherBean 做一些事情
        }
    }
  • BeanClassLoaderAware:获取类加载器

    可以通过实现这个接口的 setBeanClassLoader() 方法来获取类加载器。这在需要动态加载类或者资源时非常有用,便于实现插件化架构

    public class MyBean implements BeanClassLoaderAware {
        private ClassLoader classLoader;
    
        @Override
        public void setBeanClassLoader(ClassLoader classLoader) {
            this.classLoader = classLoader;
        }
    
        public void loadClass(String className) throws ClassNotFoundException {
            Class<?> clazz = classLoader.loadClass(className);
            // 使用 clazz 做一些事情
        }
    }

这三个接口的实现类会被忽略掉,Spring 不会对它们进行依赖注入,因为它们会在初始化阶段获取与容器相关的信息,而这时容器还没有完全初始化。

这里的 super() 又调用了 AbstractBeanFactory 的构造函数,不过这个构造函数是空的。

总之,这个构造方法就是实例化了一堆工厂类。没有搞个大新闻。

扫描包

点击查看扫描包源码解读

接着调用 scan(basePackages) 方法:

@Override
public void scan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")
        .tag("packages", () -> Arrays.toString(basePackages));
    // 扫描包(下文会详细介绍)
    this.scanner.scan(basePackages);
    scanPackages.end();
}

继续看 ClassPathBeanDefinitionScannerscan() 方法:

public int scan(String... basePackages) {
    // 获取当前 BeanDefinition 的数量
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

    // 扫描包(下文会详细介绍)
    doScan(basePackages);

    // 注册注解处理器
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    // 返回本次注册的 BeanDefinition 的数量
    return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

继续看 doScan() 方法:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");

    // BeanDefinitions 使用了一个 LinkedHashSet 来存储扫描到的 BeanDefinition
    // 每个元素都包含了 BeanDefinition 和 Bean 名称的二元组
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();

    // 遍历需要扫描的包
    for (String basePackage : basePackages) {
        // 获取包里所有符合条件的类以供筛选(下文会详细介绍)
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        
        // 遍历候选类
        for (BeanDefinition candidate : candidates) {

            // 获取作用域并绑定
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());

            // 生成 Bean 名称,如果指定了 Bean 名称则使用指定的名称
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

            // 对 AbstractBeanDefinition 进行后处理
            if (candidate instanceof AbstractBeanDefinition abstractBeanDefinition) {
                postProcessBeanDefinition(abstractBeanDefinition, beanName);
            }
            // 处理类上的通用注解(如 @Lazy、@Primary、@DependsOn)
            if (candidate instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations(annotatedBeanDefinition);
            }

            // 检查 Bean 是否可以注册
            if (checkCandidate(beanName, candidate)) {

                // 封装 BeanDefinition 和 beanName 到 BeanDefinitionHolder
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 根据作用域代理模式生成代理(即处理作用域为 request/session 的 Bean)
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

                // 将 BeanDefinitionHolder 加入到结果集,并注册到容器中(下文会详细介绍)
                beanDefinitions.add(definitionHolder);
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

这个函数完成了包扫描的主要流程,包括:

  1. 遍历所有包路径并找到候选 Bean
  2. 为每个候选 Bean 处理其作用域、生成 Bean 名称、后处理 BeanDefinition、处理通用注解
  3. 检查 Bean 是否可以注册,如果可以,则应用作用域代理模式(作用域为 request/session)并注册 BeanDefinition
  4. 返回注册的 BeanDefinition 集合

接下来,我们来看当中具体的几个方法:

  • findCandidateComponents() 方法:

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        // 不存在组件索引 且 检查当前配置的包含过滤器支持索引查询
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            // 执行索引加速扫描(下文会详细介绍)
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else {
            // 执行常规路径扫描(下文会详细介绍)
            return scanCandidateComponents(basePackage);
        }
    }

    组件索引是 Spring 提供的一种加速扫描的机制。Spring 在编译时生成一个索引文件(META-INF/spring.components),记录所有带有特定注解(如 @Component)的类,避免运行时扫描类路径。它可以显著加快大型应用的启动速度。

    • addCandidateComponentsFromIndex() 方法会直接从索引中获取 Bean。它会:

      1. 先找出属于 basePackage 的类
      2. 遍历这些类,检查是否匹配当前的 includeFilters,如果匹配则添加到候选类中
      3. 对于匹配的类生成 ScannedGenericBeanDefinition

      我们就不细看这个函数了。

    • scanCandidateComponents() 方法:

      private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
          Set<BeanDefinition> candidates = new LinkedHashSet<>();
          try {
              // ​转换包路径为资源路径,类似 classpath*:com/example/**/*.class
              // 其中,classpath* 表示扫描所有类路径下的资源
              String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                  resolveBasePackage(basePackage) + '/' + this.resourcePattern;
              
              // 获取所有 .class 资源(包括 jar 包)
              Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
      
              boolean traceEnabled = logger.isTraceEnabled();
              boolean debugEnabled = logger.isDebugEnabled();
      
              // 遍历资源
              for (Resource resource : resources) {
      
                  // 获取文件名
                  String filename = resource.getFilename();
      
                  // 忽略 CGLIB 生成的类(即文件名包含 $$)
                  if (filename != null && filename.contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
                      continue;
                  }
      
                  if (traceEnabled) {
                      logger.trace("Scanning " + resource);
                  }
      
                  try {
                      // 通过反射获取类的元数据
                      MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
      
                      // 根据过滤器包含或排除一些类
                      // 默认包含 @Component、@Service、@Repository、@Controller、@Configuration
                      if (isCandidateComponent(metadataReader)) {
      
                          // 将类的元数据封装为 ScannedGenericBeanDefinition
                          // 包含了类名、作用域、是否懒加载等信息
                          ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                          sbd.setSource(resource);
      
                          // 验证类是否符合条件
                          // 必须是具体类、有可实例化的构造方法、如果是内部类则必须为静态类
                          if (isCandidateComponent(sbd)) {
                              if (debugEnabled) {
                                  logger.debug("Identified candidate component class: " + resource);
                              }
                              
                              candidates.add(sbd);
                          }
      
          /* 省略一堆异常处理 */
      
          return candidates;
      }

      可以看到,这个方法会:

      1. 将包路径转换为资源路径
      2. 获取所有符合条件的资源,包括 jar 包
      3. 遍历资源,获取类的元数据
      4. 过滤出 @Component@Service@Repository@Controller@Configuration 注解的类
      5. 将类的元数据封装为 ScannedGenericBeanDefinition(包含了类名、作用域、是否懒加载等信息)
      6. 验证类是否符合条件(必须是具体类、有可实例化的构造方法、如果是内部类则必须为静态类)
      7. 返回符合条件的类

    总体上来讲,这里就是扫描到了所有符合条件的类。

  • registerBeanDefinition() 方法:

    protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    }

    继续跟踪 registerBeanDefinition() 方法:

    public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {
    
        // 注册主名称的 BeanDefinition(下文会详细介绍)
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
        // 如果存在别名,则注册别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

    别名是 Spring 中的一个概念,用于给 Bean 起一个或多个别名。别名可以用来简化 Bean 的引用,或者提供更具语义性的名称。别名可以这样注册:

    // 第一个是原始 Bean 的名称,后面都是别名
    @Bean(name = {"bookService", "alias1", "alias2"})
    public BookService bookService() {}

    这里的 Bean 名称就是我们在上一步获取到的。

    接下来,我们继续关注主名称的注册。registerBeanDefinition() 是个接口,我们这里用的 DefaultListableBeanFactory 的实现:

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
        // 校验必要属性是否缺失
        if (beanDefinition instanceof AbstractBeanDefinition abd) {
            try {
                abd.validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
            }
        }
    
        //  处理同名 Bean 覆盖
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isBeanDefinitionOverridable(beanName)) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else {
                logBeanDefinitionOverriding(beanName, beanDefinition, existingDefinition);
            }
            // 覆盖 BeanDefinition
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            // 如果 Bean 名称是其它 Bean 的别名
            if (isAlias(beanName)) {
                String aliasedName = canonicalName(beanName);
                if (!isBeanDefinitionOverridable(aliasedName)) {
                    if (containsBeanDefinition(aliasedName)) {
                        throw new BeanDefinitionOverrideException(
                            beanName, beanDefinition, getBeanDefinition(aliasedName));
                    }
                    else {
                        throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                            "Cannot register bean definition for bean '" + beanName +
                            "' since there is already an alias for bean '" + aliasedName + "' bound.");
                    }
                }
                else {
                    if (logger.isInfoEnabled()) {
                        logger.info("Removing alias '" + beanName + "' for bean '" + aliasedName +
                            "' due to registration of bean definition for bean '" + beanName + "': [" +
                            beanDefinition + "]");
                    }
                    removeAlias(beanName);
                }
            }
            
            if (hasBeanCreationStarted()) { // 如果已经有其它的 Bean 在初始化了,需要线程安全操作
                synchronized (this.beanDefinitionMap) {
                    // 将 BeanDefinition 存入 beanDefinitionMap
                    this.beanDefinitionMap.put(beanName, beanDefinition);
    
                    // 使用 CoW 向 List 添加新 Bean 名称
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
    
                    // 去掉手动注册的单例 Bean
                    removeManualSingletonName(beanName);
                }
            }
            else { // 如果没有其它的 Bean 在初始化
                // 直接操作
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            }
    
            // 它被用来缓存 BeanDefinitionName,加速查找
            // 重置冻结状态,使得缓存失效
            this.frozenBeanDefinitionNames = null;
        }
    
        if (existingDefinition != null || containsSingleton(beanName)) {
            // 清除解析过的元数据
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
            // 清理按类型查找的缓存
            clearByTypeCache();
        }
    
        // 记录 @Primary 注解的 Bean 名称
        if (beanDefinition.isPrimary()) {
            this.primaryBeanNames.add(beanName);
        }
    }

    这个函数考虑了很多问题:

    • 根据覆盖策略,决定是否覆盖已有的 BeanDefinition
    • 如果 Bean 名称是其它 Bean 的别名,则先移除别名
    • 如果已经有其它的 Bean 在初始化,则需要线程安全操作
    • 清除各类缓存
    • 记录 @Primary 注解的 Bean 名称

扫描包的过程其实就是将指定包下的类换成 Bean 存储到一个名为 beanDefinitions 的 LinkedHashSet 中,集合的每个元素都包含了 BeanDefinition 和 Bean 名称的二元组。然后,再将其挨个取出检查后放入 beanDefinitionMap。

最终,我们得到的是名字和 BeanDefinition 的映射关系。

刷新容器

点击查看刷新容器源码解读

refresh() 方法在 AbstractApplicationContext 中:

@Override
public void refresh() throws BeansException, IllegalStateException {
    // 上锁,防止一个 refresh() 还没结束,另一个 refresh() 就开始了
    this.startupShutdownLock.lock();
    try {
        // startupShutdownThread 记录当前执行线程,用于后续关闭时校验线程一致性
        this.startupShutdownThread = Thread.currentThread();

        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

        // 记录容器启动时间、初始化环境变量、发布 ApplicationContextEvent 早期事件(下文会详细介绍)
        prepareRefresh();

        // 创建或者刷新 BeanFactory(如果是 XML 配置则会在这里创建)(下文会详细介绍)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 配置类加载器、EL 解析器、注册内置 Bean 等(下文会详细介绍)
        prepareBeanFactory(beanFactory);
        try {
            // 模板方法供子类扩展,例如 GenericWebApplicationContext 会在这里准备好 Spring Web 所需的 Bean(下文会详细介绍)
            postProcessBeanFactory(beanFactory);
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            // 调用所有的 BeanFactoryPostProcessor
            // 解析 @Configuration、@Bean、@ComponentScan 等注解
            // 加载额外的 BeanDefinition
            invokeBeanFactoryPostProcessors(beanFactory);
            // 注册 BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();

            // 初始化 i18n(需要名为 messageSource 的 Bean)
            initMessageSource();
            //初始化事件多播器,用于发布事件到监听器
            initApplicationEventMulticaster();

            // 模板方法,供子类初始化特殊的 Bean
            onRefresh();
            // 注册 ApplicationListener Bean 到事件多播器,并发布早期事件
            registerListeners();

            // 完成 BeanFactory 的初始化
            // 初始化所有非延迟单例 Bean、触发 BeanPostProcessor、解决循环依赖等(下文会详细介绍)
            finishBeanFactoryInitialization(beanFactory);

            // 发布容器刷新完成事件,启动生命周期处理器
            finishRefresh();
        }
        catch (RuntimeException | Error ex ) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                    "cancelling refresh attempt: " + ex);
            }
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
        finally {
            contextRefresh.end();
        }
    }
    finally {
        // 释放锁
        this.startupShutdownThread = null;
        this.startupShutdownLock.unlock();
    }
}

这个函数我们先不急着完全理解,先看其中几个关键的函数:

  • prepareRefresh()

    protected void prepareRefresh() {
        // 记录开始时间
        this.startupDate = System.currentTimeMillis();
        // 标记为活动状态,防止并发异常
        this.closed.set(false);
        this.active.set(true);
    
        if (logger.isDebugEnabled()) {
          if (logger.isTraceEnabled()) {
            logger.trace("Refreshing " + this);
          }
          else {
            logger.debug("Refreshing " + getDisplayName());
          }
        }
    
        // 模板方法,供子类扩展,例如 GenericWebApplicationContext 会在这里创建 DefaultListableBeanFactory
        // 用于初始化和环境变量(下文会详细介绍)
        initPropertySources();
    
        // 确认所有 @Require 的属性都能够被解析
        getEnvironment().validateRequiredProperties();
    
        // 备份早期事件监听器,防止多次注册
        if (this.earlyApplicationListeners == null) {
          this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        }
        else {
          this.applicationListeners.clear();
          this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
    
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

    这个函数是 Spring 容器刷新过程中的准备阶段。其中支持了一个 initPropertySources() 的模板方法,供子类扩展。

    例如,GenericWebApplicationContext 中的实现:

    @Override
    protected void initPropertySources() {
      ConfigurableEnvironment env = getEnvironment();
      if (env instanceof ConfigurableWebEnvironment configurableWebEnv) {
        configurableWebEnv.initPropertySources(this.servletContext, null);
      }
    }

    这个子类覆写的方法会调用 ConfigurableWebEnvironmentinitPropertySources() 方法,初始化属性源。它会将 ServletContext 和 ServletConfig 中的属性源添加到环境变量中。

  • obtainFreshBeanFactory()

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 获取 DefaultListableBeanFactory(下文会详细介绍)
        refreshBeanFactory();
        // 返回 BeanFactory
        return getBeanFactory();
    }

    这里的两个函数都使用了接口,以适配 XML 和注解两种配置。

    • 对于 XML 配置,具体的实现在 AbstractRefreshableApplicationContext 中,因为需要支持多次刷新上下文。每次调用 refresh() 时,会 ​销毁旧的 BeanFactory,重新创建并加载新的 BeanFactory。
    • 对于注解配置,具体的实现在 GenericWebApplicationContext 中,仅需一次初始化。它的 BeanFactory 是固定的(DefaultListableBeanFactory),仅在首次初始化时创建,后续刷新不重建

    我们来看 GenericWebApplicationContext

    @Override
    protected final void refreshBeanFactory() throws IllegalStateException {
        if (!this.refreshed.compareAndSet(false, true)) {
            throw new IllegalStateException(
                "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        }
        // 使用了 DefaultListableBeanFactory(下文会详细介绍)
        this.beanFactory.setSerializationId(getId());
    }

    这里的 setSerializationId(getId()) 是为了在序列化时使用当前 ApplicationContext 的 ID。

    public void setSerializationId(@Nullable String serializationId) {
        if (serializationId != null) {
            serializableFactories.put(serializationId, new WeakReference<>(this));
        }
        else if (this.serializationId != null) {
            serializableFactories.remove(this.serializationId);
        }
        this.serializationId = serializationId;
    }

    可以看到,DefaultListableBeanFactory 中使用了一个 WeakReference 来保存 BeanFactory 的引用,并将其放入 serializableFactories 中。

    这里,BeanFactory 实例仅能有一个,如果已经存在,就会直接覆盖。

    总体上来看,obtainFreshBeanFactory() 方法分 XML 和注解两种配置,用不同的方式实例化了 BeanFactory。

  • prepareBeanFactory()

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 基础配置
        // 类加载器
        beanFactory.setBeanClassLoader(getClassLoader());
        // SpEL 解析器,例如 #{...}
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        // 属性编辑器,例如 @Value("classpath:config.xml")
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
        // 处理 Aware 接口(下文会详细介绍)
        // 在 Bean 初始化前后回调 Aware 接口方法,如 setApplicationContext()
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        // 处理过后,Autowire 时就可以忽略它们了
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
    
        // 注册可解析依赖
        // 当 Bean 需要注入 BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext 时,直接返回容器实例
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    
        // 注册事件监听器
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    
        // 加载时织入(LTW)配置(下文会详细介绍)
        // 处理 LoadTimeWeaverAware 接口,为 Bean 注入 LoadTimeWeaver
        if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // 临时的 ClassLoader,确保动态生成的代理类可以被正确加载
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    
        // 注册环境变量和属性配置、JVM 系统属性、系统环境变量、启动指标收集器的 Bean
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
        if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
            beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
        }
    }

    这个函数主要做了以下几件事:

    • 设置类加载器、SpEL 解析器、属性编辑器

    • Aware 接口处理

      ApplicationContextAware 接口的实现类会在初始化时调用 setApplicationContext() 方法,获取当前 ApplicationContext 的引用。常用于动态获取其它 Bean、访问容器服务(如国际化、资源加载)或发布自定义事件时。

      public class MyBean implements ApplicationContextAware {
          private ApplicationContext applicationContext;
      
          @Override
          public void setApplicationContext(ApplicationContext applicationContext) {
              this.applicationContext = applicationContext;
          }
      
          public void doSomething() {
              UserService userService = applicationContext.getBean(UserService.class);
              context.publishEvent(new MyCustomEvent(this));
          }
      }
    • 依赖解析

    • 事件监听

      事件是 Spring 中的一个重要概念,用于实现松耦合的组件之间的通信。Spring 提供了事件发布和监听的机制,可以让组件在发生特定事件时通知其它组件。

      它可以用于

      • 跨模块通信(如订单创建后触发库存更新)
      • 异步处理(如邮件发送、日志记录)
      • 系统状态监控(如应用启动、停止、异常处理)

      这里是一个简单的例子:

      // 定义事件
      public class OrderCreateEvent extends ApplicationEvent {
          private final Order order;
      
          public OrderCreateEvent(Object source, Order order) {
              super(source);
              this.order = order;
          }
      
          public Order getOrder() {
              return order;
          }
      }
      
      // 发布事件
      @Service
      public class OrderService {
          @Autowired
          private ApplicationEventPublisher eventPublisher;
      
          public void createOrder(Order order) {
              // 创建订单逻辑
              eventPublisher.publishEvent(new OrderCreateEvent(this, order));
          }
      }
      
      // 监听事件
      @Component
      public class OrderEventListener {
          @EventListener
          public void handleOrderCreate(OrderCreateEvent event) {
              log.info("Order created: {}", event.getOrder());
          }
      }
    • 加载时织入(LTW)配置

      LTW 是 Spring 提供的一种机制,用于在运行时将切面织入到目标类中。它允许开发者在不修改源代码的情况下,将切面应用到现有的类上。

      这里主要是 LoadTimeWeaverAware 接口的处理。

      要使用 LoadTimeWeaverAware 接口,首先需要在配置类加上 @EnableLoadTimeWeaving 注解。

      然后实现 LoadTimeWeaverAware 接口:

      @Component
      public class MyLoadTimeWeaverAware implements LoadTimeWeaverAware {
          private LoadTimeWeaver loadTimeWeaver;
      
          @Override
          public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
              this.loadTimeWeaver = loadTimeWeaver;
          }
      
          // 其他方法
      }

      然后,定义一个切面:

      @Aspect
      @Component
      public class MyAspect {
          @Before("execution(* com.example.service.*.*(..))")
          public void beforeAdvice(JoinPoint joinPoint) {
              log.info("Before method: {} ", joinPoint.getSignature());
          }
      }

      最后,运行时织入会在应用启动时自动将切面应用到目标类中。

    • 环境集成

  • postProcessBeanFactory()

    我们只看 GenericWebApplicationContext 中的实现:

    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        if (this.servletContext != null) {
            // 若有一个 Bean 实现 ServletContextAware,Spring 会调用其 setServletContext() 方法注入当前 ServletContext
            beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
            // 忽略 ServletContextAware 接口,避免在 Autowire 时再次被注入
            beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        }
    
        // 向 BeanFactory 注册 Web 环境特有的作用域
        // 包含了 request、session、application
        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    
        // 将 Web 环境特有的对象注册为单例 Bean,供其他组件依赖注入
        // 包括了 ServletContext、ServletConfig、ContextParameters、ContextAttributes
        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
    }

    这个函数整体上就是为 Spring Web 完成了一些配置。

  • finishBeanFactoryInitialization()

    我们跳过了其它一些不太重要的函数,直接来到最后一步。这个函数会完成 BeanFactory 的初始化:

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // 初始化引导执行器
        if (beanFactory.containsBean(BOOTSTRAP_EXECUTOR_BEAN_NAME) &&
            beanFactory.isTypeMatch(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class)) {
            beanFactory.setBootstrapExecutor(
                beanFactory.getBean(BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class));
        }
    
        // 初始化转换服务(即 Bean 的类型为 ConversionService,用于 Bean 的类型转换)
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
            beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
        }
    
        // 注册默认的嵌入式值解析器,用于解析 ${...} 占位符
        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
        }
    
        // 初始化 BeanFactoryInitializer 的 Bean
        // BeanFactoryInitializer 是一个回调接口,用于在 BeanFactory 完成初始化后执行一些自定义的初始化逻辑
        String[] initializerNames = beanFactory.getBeanNamesForType(BeanFactoryInitializer.class, false, false);
        for (String initializerName : initializerNames) {
            beanFactory.getBean(initializerName, BeanFactoryInitializer.class).initialize(beanFactory);
        }
    
        // 初始化 LoadTimeWeaverAware 的 Bean
        // LoadTimeWeaverAware Bean 需要在类加载时织入切面,必须尽早初始化以注册字节码转换器
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        for (String weaverAwareName : weaverAwareNames) {
            try {
                beanFactory.getBean(weaverAwareName, LoadTimeWeaverAware.class);
            }
            catch (BeanNotOfRequiredTypeException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Failed to initialize LoadTimeWeaverAware bean '" + weaverAwareName +
                        "' due to unexpected type mismatch: " + ex.getMessage());
                }
            }
        }
    
        // 清理 LTW 相关的临时 ClassLoader
        beanFactory.setTempClassLoader(null);
    
        // 已注册的 Bean 不再允许被修改或后处理,提升性能
        beanFactory.freezeConfiguration();
    
        // 初始化非延迟单例 Bean(下文会详细介绍)
        beanFactory.preInstantiateSingletons();
    }

    这个函数根据优先级,依次初始化了:

    • 引导执行器和转换服务
    • LTW 相关的 Bean
    • 普通的单例 Bean

    总体来讲,就是在真正初始化 Bean 前将一些可能依赖的 Bean 初始化好。

    跟踪最后的初始化函数:

    @Override
    public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }
    
        // 先拷贝一份 Bean 名称,因为后面回往其中添加新的 Bean 名称,破坏遍历的稳定性
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
        for (String beanName : beanNames) {
            // 合并父子类的 BeanDefinition
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 仅处理非抽象、非延迟的单例 Bean
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                // FactoryBean 需要特殊处理进行提前实例化(下文会详细介绍)
                if (isFactoryBean(beanName)) {
                    Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                    if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
                        getBean(beanName);
                    }
                }
                else {
                    // 实例化普通 Bean(下文会详细介绍)
                    getBean(beanName);
                }
            }
        }
    
        // 后处理
        for (String beanName : beanNames) {
            // 获取实例单例
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
                StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
                    .tag("beanName", beanName);
                // 如果实现了 SmartInitializingSingleton 接口,则调用 afterSingletonsInstantiated()(下文会详细介绍)
                smartSingleton.afterSingletonsInstantiated();
                smartInitialize.end();
            }
        }
    }

    这里除了实例化普通 Bean,还特殊处理了 SmartFactoryBean 和 SmartInitializingSingleton。

    • SmartFactoryBeanFactoryBean 的子接口,提供了 isEagerInit() 方法,用于判断是否需要提前实例化。

      public class mySmartFactoryBean implements SmartFactoryBean<MyBean> {
          @Override
          public boolean isEagerInit() {
              return true;
          }
      
         @Override
          public MyBean getObject() {
              return new MyBean();
          }
      }
    • SmartInitializingSingleton 是一个回调接口,用于在所有单例 Bean 实例化完成后执行一些自定义的初始化逻辑。

      @Component
      public class MySmartInitializingSingleton implements SmartInitializingSingleton {
          @Override
          public void afterSingletonsInstantiated() {
              log.info("All singletons are instantiated");
              // 自定义初始化逻辑
          }
      }

    接下来,我们来看一下 getBean() 方法。这个方法巨长,但逻辑并不复杂:

    protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {
        
        // 处理名称,主要是去除 FactoryBean 的前缀 &
        String beanName = transformedBeanName(name);
        Object beanInstance;
    
        // 检查是否已经实例化过,如果已经实例化过,直接返回
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isTraceEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
    
        else {
            // 防止原型 Bean 循环依赖
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
    
            // 如果 Bean 有父类且没有实例化过
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory abf) {
                    return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
                }
                else if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else if (requiredType != null) {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }
    
            // 标记为已创建,防止并发下多次实例化
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
    
            StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
                .tag("beanName", name);
                
            try {
                if (requiredType != null) {
                  beanCreation.tag("beanType", requiredType::toString);
                }
    
                // 合并父子类的 BeanDefinition
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
    
                // 获取依赖的 Bean,确保依赖先于当前 Bean 被实例化
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        // 检查循环依赖,检测到就抛出异常
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
    
                        // 注册依赖关系
                        registerDependentBean(dep, beanName);
                        try {
                            // 递归初始化依赖 Bean
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                        catch (BeanCreationException ex) {
                            if (requiredType != null) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Failed to initialize dependency '" + ex.getBeanName() + "' of " +
                                        requiredType.getSimpleName() + " bean '" + beanName + "': " +
                                        ex.getMessage(), ex);
                            }
                            throw ex;
                        }
                    }
                }
    
                // 按照不同的作用域实例化 Bean
    
                // 单例模式
                if (mbd.isSingleton()) {
                    // 三级缓存解决循环依赖(下文会详细介绍)
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
    
                // 原型模式,没有缓存,直接实例化
                else if (mbd.isPrototype()) {
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        afterPrototypeCreation(beanName);
                    }
                    beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }
    
                // 自定义作用域,包括了 request、session 等
                else {
                    String scopeName = mbd.getScope();
                    if (!StringUtils.hasLength(scopeName)) {
                        throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
                    }
                    Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
    
                        // BeanFactory 实例,获取其生产的 Bean 实例
                        beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        throw new ScopeNotActiveException(beanName, scopeName, ex);
                    }
                }
            }
            catch (BeansException ex) {
                beanCreation.tag("exception", ex.getClass().toString());
                beanCreation.tag("message", String.valueOf(ex.getMessage()));
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
            finally {
                beanCreation.end();
                if (!isCacheBeanMetadata()) {
                    clearMergedBeanDefinition(beanName);
                }
            }
        }
    
        // 返回适配后的 Bean 实例,确保类型正确,可能会进行类型转换
        return adaptBeanInstance(name, beanInstance, requiredType);
    }

    总之,这个函数就是先去做了循环依赖检查,然后分单例、原型、自定义三种作用域,分别实例化 Bean。

    当然,如果父类还没实例化完,它会先实例化父类。

    有必要讲一下这里是如何实现三级缓存的。三级缓存的核心思想是提前暴露未初始化的 Bean 引用,允许循环依赖。

    // 三级缓存,存放 Bean 的 ObjectFactory
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
    // 二级缓存,存放早期暴露的 Bean,未完成属性填充和初始化
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    
    // 一级缓存,存放已完成属性填充和初始化的 Bean
    private final Map<String, Object> singletons = new HashMap<>(256);

    为了摸清三级缓存的使用,我们来看 createBean() 方法:

    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {
    
        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;
    
        // 根据类名解析出 Bean 的 Class
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        // 如果这个类是动态解析的(例如 @Configuration 中的 @Bean),则需要克隆出新的 RootBeanDefinition
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
            try {
                // 确认是否有 @Override,如果没有则不需要 CGLIB 增强
                mbdToUse.prepareMethodOverrides();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
            }
        }
    
        // 调用所有 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法
        // 用于 AOP 代理和自定义代理对象等
        try {
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
        }
    
        // 真正实例化 Bean(下文会详细介绍)
        try {
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
          throw ex;
        }
        catch (Throwable ex) {
          throw new BeanCreationException(
              mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

    这个函数主要是把动态类和 PostProcessor(如代理类)单独拎出来处理了下。

    我们继续看 doCreateBean() 方法:

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {
        
        // 创建 Bean 的原始实例
        // 可能通过构造函数、工厂方法、CGLIB 等方式创建
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            // 创建 Bean 实例(下文会详细介绍)
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
    
        // 获取 Bean 的类型
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }
    
        // 执行后处理器
        // @Autowired、@Value 等注解注入元数据
        // @PostConstruct、@PreDestroy 等生命周期回调
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
                }
                mbd.markAsPostProcessed();
            }
        }
    
        // 提前暴露 Bean 引用
        // 将 Bean 的 ObjectFactory 存入 singletonFactories,允许其他 Bean 在依赖注入时获取早期引用
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
    
        // 初始化 Bean 实例
        Object exposedObject = bean;
        try {
            // 填充属性(下文会详细介绍)
            populateBean(beanName, mbd, instanceWrapper);
            // 执行初始化回调
            // 这个函数会执行 @PostConstruct 注解的方法,但竟然标注了 @Deprecated!
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
                throw bce;
            }
            else {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
            }
        }
    
        // 处理早期冲突,避免在 BeanPostProcessor 之外过早访问未初始化的 Bean
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = CollectionUtils.newLinkedHashSet(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                            "Bean with name '" + beanName + "' has been injected into other beans [" +
                            StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                            "] in its raw version as part of a circular reference, but has eventually been " +
                            "wrapped. This means that said other beans do not use the final version of the " +
                            "bean. This is often the result of over-eager type matching - consider using " +
                            "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }
    
        // 注册实现了 DisposableBean 接口的 Bean
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }
    
        return exposedObject;
    }

    这个函数依次完成了:

    1. 实例化 Bean
    2. 提前暴露 Bean 引用
    3. 填充属性
    4. 执行初始化回调和代理生成
    5. 处理早期冲突
    6. 销毁注册

    下面,我们来看看填充属性和初始化回调的实现:

    • createBeanInstance() 方法

      该方法会根据 Bean 的定义和参数创建一个新的 Bean 实例。它会考虑到构造函数、工厂方法、CGLIB 代理等多种情况。

      protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
          // 根据 Bean 定义中的类名解析出具体的 Class
          Class<?> beanClass = resolveBeanClass(mbd, beanName);
      
          // 必须是 public 的类
          if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
          }
      
          // Bean 定义中配置了自定义的 Supplier,直接使用它创建实例
          if (args == null) {
              Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
              if (instanceSupplier != null) {
                  return obtainFromSupplier(instanceSupplier, beanName, mbd);
              }
          }
      
          // 如果 Bean 定义中配置了工厂方法,则使用它创建实例
          if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
          }
          boolean resolved = false;
          boolean autowireNecessary = false;
          if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
              if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
              }
            }
          }
          if (resolved) {
            if (autowireNecessary) {
              return autowireConstructor(beanName, mbd, null, null);
            }
            else {
              return instantiateBean(beanName, mbd);
            }
          }
      
          // 复用缓存的构造函数解析结果
          // 避免重复解析构造函数,提升性能
          Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
          if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
              mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
              return autowireConstructor(beanName, mbd, ctors, args);
          }
      
          // 确定候选构造函数
          ctors = mbd.getPreferredConstructors();
          if (ctors != null) {
            return autowireConstructor(beanName, mbd, ctors, null);
          }
      
          // 构造函数自动装配
          return instantiateBean(beanName, mbd);
      }

      这个函数确定了拿什么实例化 Bean,它会依次尝试:

      • 自定义的 Supplier
      • 工厂方法
      • @Autowired 构造函数
      • 默认构造函数
      • 自定义的 Supplier 主要是指 @Bean 注解中的 Supplier,它会在 Bean 定义中被解析出来。

        例如:

        @Configuration
        public class MyConfig {
            @Bean
            public Supplier<UserService> userServiceSupplier() {
                return () -> {
                    UserService userService = new UserService();
                    userService.init();
                    return userService;
                };
            }
        
            @Bean
            public UserService userService(Supplier<UserService> userServiceSupplier) {
                return userServiceSupplier.get();
            }
        }
        
        @FunctionalInterface
        public interface Supplier<T> {
            T get();
        }

        这个函数使得在实例化 UserService 时,可以使用 userServiceSupplier 中定义的逻辑。

      • 工厂方法允许开发者将对象创建逻辑封装在工厂类中。它和 supplier 差不多,不再赘述。

      方便起见,我们看最后一个 instantiateBean() 方法:

      protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
          try {
              // 实例化有两种策略:反射调用和 CGLIB
              Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
              // 包装并初始化 Bean
              BeanWrapper bw = new BeanWrapperImpl(beanInstance);
              initBeanWrapper(bw);
              return bw;
          }
          catch (Throwable ex) {
              throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
          }
      }

      继续跟踪 instantiate() 方法:

      @Override
      public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
            if (!bd.hasMethodOverrides()) {
                Constructor<?> constructorToUse;
                // 如果不存在方法覆写,那就使用 Java 反射进行实例化
                // 获取构造函数
                synchronized (bd.constructorArgumentLock) {
                    constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                    if (constructorToUse == null) {
                        Class<?> clazz = bd.getBeanClass();
                        if (clazz.isInterface()) {
                            throw new BeanInstantiationException(clazz, "Specified class is an interface");
                        }
                        try {
                            // 获取默认无参构造函数
                            constructorToUse = clazz.getDeclaredConstructor();
                            bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                        }
                        catch (Throwable ex) {
                            throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                        }
                    }
                }
                return BeanUtils.instantiateClass(constructorToUse);
            }
            else {
                // 否则使用 CGLIB
                return instantiateWithMethodInjection(bd, beanName, owner);
            }
        }

      没什么好说的,就是用反射找到构造函数并调用。

      往下挖了这么多层,不要忘了我们最开始看的是 createBeanInstance() 方法。

      我们看到,它分构造函数、工厂方法、CGLIB 代理等多种情况,分别对应不同的实例化策略。最终,会返回一个未初始化的实例。

      接下来,我们继续看它是如何填充属性的:

    • populateBean() 方法:

      protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
          // 确认已经成功实例化 Bean
          if (bw == null) {
              if (mbd.hasPropertyValues()) {
                  throw new BeanCreationException(
                      mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
              }
              else {
                  return;
              }
          }
      
          // Record 类型不可变,不允许修改属性值
          if (bw.getWrappedClass().isRecord()) {
              if (mbd.hasPropertyValues()) {
                  throw new BeanCreationException(
                      mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
              }
              else {
                  return;
              }
          }
      
          // 自定义依赖注入
          if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
              for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
                  if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                      return;
                  }
              }
          }
      
          // 处理自动装配
          PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
          int resolvedAutowireMode = mbd.getResolvedAutowireMode();
          if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
              MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
              // 按名称 Autowire
              if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                  autowireByName(beanName, mbd, bw, newPvs);
              }
              // 按类型 Autowire
              if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                  autowireByType(beanName, mbd, bw, newPvs);
              }
              pvs = newPvs;
          }
      
          // 处理属性值
          if (hasInstantiationAwareBeanPostProcessors()) {
              if (pvs == null) {
                  pvs = mbd.getPropertyValues();
              }
              for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
                  // 修改属性值
                  PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                  if (pvsToUse == null) {
                      return;
                  }
                  pvs = pvsToUse;
              }
          }
      
          // 依赖检查
          boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
          if (needsDepCheck) {
              PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
              checkDependencies(beanName, mbd, filteredPds, pvs);
          }
      
          // 将属性值应用到 Bean 实例
          if (pvs != null) {
              applyPropertyValues(beanName, mbd, bw, pvs);
          }
      }

      它做了这么几件事:

      1. 校验是否可以填充属性
      2. 处理自动装配
      3. 后处理扩展
      4. 完成注入

      后处理扩展就是调用 InstantiationAwareBeanPostProcessor 接口的 postProcessProperties() 方法,允许开发者在属性填充前后进行自定义处理。

      例如:

      @Component
      public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
          @Override
          public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
              for (PropertyValue pv : pvs.getPropertyValues()) {
                  if ("name".equals(pv.getName())) {
                      pvs.addPropertyValue("name", "newName");
                  }
              }
              return pvs;
          }
      }

好!啰啰嗦嗦地说了这么多,总算看完了 Spring 刷新容器的过程。

这个过程中,Spring 主要就是将 BeanDefinition 创建了实例并注入了属性。

总结

我们最后来总结一些 IoC 的流程:

扫描包

  1. 遍历所有包路径并找到候选 Bean

    • 直接从索引中获取

      1. 先找出属于 basePackage 的类
      2. 遍历这些类,检查是否匹配当前的 includeFilters,如果匹配则添加到候选类中
      3. 对于匹配的类生成 ScannedGenericBeanDefinition
    • 通过扫描包目录获取

      1. 将包路径转换为资源路径
      2. 获取所有符合条件的资源,包括 jar 包
      3. 遍历资源,获取类的元数据
      4. 过滤出 @Component@Service@Repository@Controller@Configuration 注解的类
      5. 将类的元数据封装为 ScannedGenericBeanDefinition(包含了类名、作用域、是否懒加载等信息)
      6. 验证类是否符合条件(必须是具体类、有可实例化的构造方法、如果是内部类则必须为静态类)
      7. 返回符合条件的类
  2. 为每个候选 Bean 处理其作用域、生成 Bean 名称、后处理 BeanDefinition、处理通用注解

  3. 检查 Bean 是否可以注册,如果可以,则应用作用域代理模式(作用域为 request/session)并注册 BeanDefinition

    1. 注册主要名称

      • 根据覆盖策略,决定是否覆盖已有的 BeanDefinition
      • 如果 Bean 名称是其它 Bean 的别名,则先移除别名
      • 如果已经有其它的 Bean 在初始化,则需要线程安全操作
      • 清除各类缓存
      • 记录 @Primary 注解的 Bean 名称
    2. 注册别名

  4. 返回注册的 BeanDefinition 集合

刷新容器

  1. 记录容器启动时间并初始化

    • 初始化属性源
    • 确认 @Require 属性都已满足
    • 备份早期事件监听器
  2. 创建或刷新 BeanFactory

    • XML 配置

      ​销毁旧的 BeanFactory,重新创建并加载新的 BeanFactory

    • 注解配置

      仅在首次初始化时创建 BeanFactory,后续刷新不重建

  3. 配置类加载器、EL 解析器、注册内置 Bean 等

    1. 设置类加载器、SpEL 解析器、属性编辑器
    2. 处理 ApplicationContextAware 接口
    3. 依赖解析
    4. 事件监听
    5. 加载时织入(LTW)配置,处理 LoadTimeWeaverAware 接口
    6. 环境集成
  4. 调用所有的 BeanFactoryPostProcessor

    为 Spring Web 完成基础配置

  5. 初始化 i18n

  6. 初始化事件多播器

  7. 初始化特殊的 Bean

  8. 初始化所有非延迟单例 Bean、触发 BeanPostProcessor、解决循环依赖

    1. 初始化引导执行器和转换服务

    2. 初始化 LTW 相关的 Bean

    3. 初始化普通的单例 Bean

      1. 特殊处理 SmartFactoryBean

      2. 实例化普通 Bean

        执行循环依赖检查,如果父类还没实例化完,它会先实例化父类。

        1. 单例实例化

          1. 处理 InstantiationAwareBeanPostProcessor

          2. 实例化 Bean

            • 使用自定义的 Supplier
            • 使用工厂方法
            • @Autowired 构造函数
            • 默认构造函数
          3. 提前暴露 Bean 引用

          4. 填充属性

            1. 校验是否可以填充属性
            2. 处理自动装配
            3. 后处理扩展(InstantiationAwareBeanPostProcessor)
            4. 完成注入
          5. 执行初始化回调

          6. 处理早期冲突

          7. 注册实现了 DisposableBean 接口的 Bean

        2. 原型实例化

        3. 自定义作用域实例化

      3. 特殊处理 SmartInitializingSingleton

  9. 发布容器刷新完成事件,启动生命周期处理器

Bean 生命周期

根据以上讨论,我们可以总结出 Bean 的生命周期:

  1. BeanDefinition 注册(不属于 Bean 生命周期)

    通过 @ComponentScan 扫描到的 Bean 会被注册到容器中

    执行 ApplicationContextAwareLoadTimeWeaverAware

  2. 实例化

    根据包扫描的结果,通过构造函数或工厂方法创建 Bean 实例

    为解决循环依赖,Spring 可能提前暴露未初始化的 Bean

  3. 依赖注入

    根据 @Value@Autowired@Resource 等注解注入属性值和依赖

    如果存在循环依赖,从三级缓存获取提前暴露的 Bean 引用

  4. Aware 接口回调

    执行 Aware 接口的回调方法

    按顺序执行 BeanNameAware $$\to$$ BeanClassLoaderAware $$\to$$ BeanFactoryAware

  5. BeanPostProcess 前置处理

    执行 BeanPostProcessorpostProcessBeforeInitialization 方法

  6. 初始化方法

    依次处理

    1. @PostConstruct 注解的方法
    2. InitializingBean 接口的 afterPropertiesSet() 方法
    3. 自定义的初始化方法
  7. BeanPostProcess 后置处理

    执行 BeanPostProcessorpostProcessAfterInitialization 方法

  8. Bean 就绪

    所有 Bean 都放入一级缓存,以供使用

  9. 销毁

    依次处理

    1. @PreDestroy 注解的方法
    2. DisposableBean 接口的 destroy() 方法
    3. 自定义的销毁方法

扩展点

上文我们已经介绍了一些扩展点,并给出了示例代码。这里我们再总结一下:

  • BeanFactoryPostProcessor

    在 BeanDefinition 加载完成后,Bean 实例化之前执行。可以修改 BeanDefinition 的属性。

    解析 ${} 占位符、处理 @Configuration 注解等都是通过这个接口实现的。

    例如,修改 Bean 的作用域:

    @Component
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
            BeanDefinition bd = beanFactory.getBeanDefinition("myBean");
            bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        }
    }
  • BeanDefinitionRegistryPostProcessor

    在 BeanDefinition 加载完成后,Bean 实例化之前执行。可以动态注册新的 BeanDefinition。

    组件扫描、@Configuration 注解等都是通过这个接口实现的。

    例如,动态注册一个 Bean:

    @Component
    public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
            registry.registerBeanDefinition("customBean", new RootBeanDefinition(CustomBean.class));
        }
    }
  • BeanPostProcessor

    在 Bean 实例化后,属性注入前执行。可以修改 Bean 的属性。

    @Autowired@Resource@PostConstruct 等都是通过这个接口实现的。

    例如,修改 Bean 的属性:

    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            if (bean instanceof MyBean) {
                ((MyBean) bean).setName("newName");
            }
            return bean;
        }
    }
  • FactoryBean

    通过实现 FactoryBean 接口,可以自定义 Bean 的创建逻辑。

    例如,创建一个单例的 UserService

    @Component
    public class UserServiceFactoryBean implements FactoryBean<UserService> {
        @Override
        public UserService getObject() {
            return new UserService();
        }
    
        @Override
        public Class<?> getObjectType() {
            return UserService.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
  • Aware

    通过实现 Aware 接口,可以获取 Spring 容器的上下文信息。

    其包括了 ApplicationContextAwareBeanFactoryAwareEnvironmentAware 等接口。

    例如,获取 ApplicationContext

    @Component
    public class MyBean implements ApplicationContextAware {
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) {
            logger.info("ApplicationContext: " + applicationContext);
        }
    }
  • 自定义作用域

  • @PostConstruct@PreDestroy

    通过这两个注解,可以在 Bean 初始化和销毁时执行自定义逻辑。

    例如:

    @Component
    public class MyBean {
        @PostConstruct
        public void init() {
            logger.info("MyBean initialized");
        }
    
        @PreDestroy
        public void destroy() {
            logger.info("MyBean destroyed");
        }
    }
  • ApplicationListener

    通过实现 ApplicationListener 接口,可以监听 Spring 容器中的事件。

    例如,监听容器刷新事件:

    @Component
    public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            logger.info("Application context refreshed: " + event.getApplicationContext());
        }
    }
  • ImportBeanDefinitionRegistrar@Import

    通过实现 ImportBeanDefinitionRegistrar 接口,可以动态注册 BeanDefinition。

    MyBatis 的 @MapperScan 扫描就是通过这个接口实现的。

    例如:

    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            registry.registerBeanDefinition("customBean", new RootBeanDefinition(CustomBean.class));
        }
    }

    然后在配置类中使用 @Import 注解:

    @Configuration
    @Import(MyImportBeanDefinitionRegistrar.class)
    public class MyConfig {
        // ...
    }
  • InstantiationAwareBeanPostProcessor

    通过实现 InstantiationAwareBeanPostProcessor 接口,可以在 Bean 实例化前后执行自定义逻辑。

    AOP 代理就是通过这个接口实现的。

    例如,修改 Bean 的属性:

    @Component
    public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
        @Override
        public boolean postProcessAfterInstantiation(Object bean, String beanName) {
            if (bean instanceof MyBean) {
                ((MyBean) bean).setName("newName");
            }
            return true;
        }
    }
  • @ConditionalCondition

    通过实现 Condition 接口,可以根据条件动态注册 BeanDefinition。

    Spring Boot 的自动配置就是通过这个接口实现的。

    例如:

    public class MyCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return context.getEnvironment().getProperty("my.property").equals("true");
        }
    }

    然后在配置类中使用 @Conditional 注解:

    @Configuration
    @Conditional(MyCondition.class)
    public class MyConfig {
        // ...
    }
  • PropertyEditorConversionService

    通过实现 PropertyEditor 接口,可以自定义属性的转换逻辑。

    例如:

    public class MyPropertyEditor extends PropertyEditorSupport {
        @Override
        public void setAsText(String text) {
            setValue(new MyBean(text));
        }
    }

    然后在配置类中注册:

    @Configuration
    public class MyConfig {
        @Bean
        public MyPropertyEditor myPropertyEditor() {
            return new MyPropertyEditor();
        }
    }
  • ApplicationContextInitializer

    通过实现 ApplicationContextInitializer 接口,可以在 Spring 容器刷新之前执行自定义逻辑。

    例如:

    public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {
            applicationContext.getEnvironment().setActiveProfiles("dev");
        }
    }

    然后在 META-INF/spring.factories 中注册:

    org.springframework.context.ApplicationContextInitializer=\
      com.example.MyApplicationContextInitializer
  • BeanNameGenerator

    通过实现 BeanNameGenerator 接口,可以自定义 Bean 的名称。

    例如:

    public class MyBeanNameGenerator implements BeanNameGenerator {
        @Override
        public String generateBeanName(AnnotatedBeanDefinition definition, BeanDefinitionRegistry registry) {
            return "myBean";
        }
    }

    然后在配置类中使用 @ComponentScan 注解:

    @Configuration
    @ComponentScan(nameGenerator = MyBeanNameGenerator.class)
    public class MyConfig {
        // ...
    }