时效提示:本文写于 2020 年,基于当时的 Spring Boot 2.x,部分 API、配置和工具版本可能已经变化,参考时请以官方最新文档为准。

背景 && 可能你想干的事

  1. Spring 程序生命周期
  2. BeanDefinition 扩展点
  3. Bean的生命周期
  4. BeanFactory生命周期
  5. FactoryBean使用
  6. Spring 事件 (refresh)
  7. application.yml => Environment
  8. 各种 aware
  9. Condition

1. Spring 程序生命周期

  1. ApplicationRunner && CommandLineRunner

调用时机=>org.springframework.boot.SpringApplication#callRunners
use by spring bean

  1. SpringApplicationRunListener

use by META-INF/spring.factories
org.springframework.boot.SpringApplicationRunListener=
com.hafiz.springbootdemo.DemoSpringApplicationRunListener

补充:Spring Boot 2.7 起,自动配置类改为在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中声明,3.0 起 spring.factories 不再支持注册自动配置;SpringApplicationRunListener、ApplicationContextInitializer 等其他扩展仍然通过 spring.factories 注册。

  1. ApplicationListener
  2. ApplicationContextInitializer

这货也是Spring框架原有的东西,这个类的主要作用就是在ConfigurableApplicationContext类型(或者子类型)的ApplicationContext做refresh之前,允许我们对ConfiurableApplicationContext的实例做进一步的设置和处理。

2. BeanDefinition 扩展点

BeanDefinition——spring bean的建模对象

Bean Definition Link
BeanDefinitionRegistryPostProcessor

3. Bean生命周期

BeanPostProcess
InstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessor

ApplicationContextAwareProcessor

BeanFactoryAware
InitializingBean
init
DisposableBean

4. BeanFactory

BeanFactoryPostProcessor

5. FactoryBean

FactoryBean 是“生产 Bean 的 Bean”:容器里注册的是这个工厂,getBean 拿到的却是 getObject() 返回的对象。适合创建过程复杂、需要封装的对象,比如给接口生成代理、构建第三方客户端。注意和 BeanFactory(容器本身)区分。

@Component("tool")
public class ToolFactoryBean implements FactoryBean<Tool> {

    @Override
    public Tool getObject() {
        // 复杂的创建逻辑写在这里,例如读取配置、生成代理对象
        return new Tool("created by factory");
    }

    @Override
    public Class<?> getObjectType() {
        return Tool.class;
    }

    @Override
    public boolean isSingleton() {
        return true;   // Spring 5 起为默认方法,默认就是 true
    }
}

// context.getBean("tool")   -> Tool 对象(getObject 的返回值)
// context.getBean("&tool")  -> ToolFactoryBean 本身(名字前加 &)

典型应用:MyBatis 的 SqlSessionFactoryBean、MapperFactoryBean(为 Mapper 接口生成代理),Spring Cloud OpenFeign 的 FeignClientFactoryBean(为 @FeignClient 接口生成客户端)。

参考:Spring 官方文档:Container Extension Points

6. Spring Event

ContextRefreshedEvent
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
RequestHandledEvent

以上是 Spring 容器自带的事件(RequestHandledEvent 只在 Web 应用中出现)。Spring Boot 启动过程还会依次发布:ApplicationStartingEvent → ApplicationEnvironmentPreparedEvent → ApplicationContextInitializedEvent → ApplicationPreparedEvent → ApplicationStartedEvent → ApplicationReadyEvent,失败时发布 ApplicationFailedEvent。

注意:容器刷新之前的事件(Starting、EnvironmentPrepared 等)发生时,用 @Component 注册的监听器还没创建,收不到;要通过 spring.factories 或 SpringApplication#addListeners 注册。

业务里更常用的是自定义事件,用来解耦:

// 1. 定义事件:Spring 4.2 起可以是任意对象,不必继承 ApplicationEvent
public class OrderCreatedEvent {
    private final Long orderId;
    public OrderCreatedEvent(Long orderId) { this.orderId = orderId; }
    public Long getOrderId() { return orderId; }
}

// 2. 发布事件
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;

    @Transactional
    public void create(Order order) {
        // ... 保存订单
        publisher.publishEvent(new OrderCreatedEvent(order.getId()));
    }
}

// 3. 监听事件
@Component
public class OrderEventListener {

    // 默认同步执行:和发布方在同一个线程、同一个事务里
    @EventListener
    public void onCreated(OrderCreatedEvent event) {
        // ...
    }

    // 事务提交成功后才执行,适合发消息、通知等不能回滚的操作
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void afterCommit(OrderCreatedEvent event) {
        // ...
    }
}
  • @EventListener 默认同步,监听器抛异常会影响发布方;需要异步时加 @Async(并开启 @EnableAsync)。

  • @TransactionalEventListener 只在有事务时触发;没有事务时默认不执行,可以设置 fallbackExecution = true。

参考:Spring 官方文档:Standard and Custom Events、Spring Boot 官方文档:Application Events and Listeners

7. Environment相关

Environment 是什么? spring 的环境,其包含了相关配置信息,bean的属性注入来源。@Value等的来源。
相关接口 EnvironmentPostProcessor detail -> org.springframework.boot.env.EnvironmentPostProcessor
应用场景1. -> 让@EnableConfigurationProperties的值注入到@Value中

应用场景2. -> 我们引入第三方的jar(巨龙单点登录)使用的是properties配置时,我们可以集成到application.yml中。

应用场景3. -> 不单纯使用application.yml 去管理Environment 可以外部化配置拆分

应用场景4. -> hook 点, 调整Environment 源数据加载顺序。调整相关的优先级等。

8. 各种Aware

各种Aware注入 如常见的注入ApplicationContextAware 用于获取 ApplicationContext。

BeanNameAware
BeanFactoryAware
SmartInitializingSingleton

9. Condition

spring.context => 核心注解@Conditional

常见复合注解 @ConditionalOnClass、 @ConditionalOnProperty 、ConditionalOnMissingBean。 扩展Conditional => SpringBootCondition

一般最常见的是ConditionalOnMissingBean 我们就可以自定义bean,让框架使用我们的bean

如 spring.session.store-type=jdbc => 可以使用内存存储session

Use In Project

  1. 一般情况注册Bean
  2. 特殊情况 META-INF/spring.factories

写在最后

以上仅仅是自己工作中总结到的一些点,Spring Boot (Spring Core) 本身扩展点就很多,如果你集成其他框架,那就更多了,所以有时间还是可以多看看源码的。

More and More