Spring 启动过程

博文目录

文章目录


内容总结

Spring启动流程详解

通常,我们说的 Spring 启动,就是构造 ApplicationContext 对象以及调用 refresh() 方法的过程。

java 复制代码
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Application.class);
context.refresh();

ApplicationContext 的定位是 Spring 的应用上下文, 负责管理和组织应用程序的各个部分. 从代码层面来说, ApplicationContext 是一个 BeanFactory, 从架构层面来说, ApplicationContext 是比 BeanFactory 更加高级的存在, 它统御 BeanFactory, EnvironmentCapable, MessageSource 等这些组件完成相应的功能, BeanFactory 只是它的一个零件而已. GenericApplicationContext 不继承 DefaultListableBeanFactory 而是将之作为一个属性, 从 BeanFactory 继承来的功能全部委托其持有的 DefaultListableBeanFactory 来执行

大致做了下面的一些事情

  • 构造了一个 DefaultListableBeanFactory 对象
  • 初始化一些基础架构组件
  • 解析配置类, 得到 BeanDefinition, 注册到 BeanFactory 中
    • 解析 @ComponentScan, 完成扫描
    • 解析 @Import
    • 解析 @Bean
    • ...
  • 初始化 MessageSource 支持国际化
  • 初始化 ApplicationEventMulticaster 支持事件机制, 将用户定义的 ApplicationListener 添加到 ApplicationContext 中
  • 创建 非懒加载的单例 Bean, 并存在 BeanFactory 的单例池中
  • 调用 Liftcycle Bean 的 start 方法
  • 发布 ContextRefreshedEvent 事件

由于 Spring 启动过程中要创建非懒加载的单例 Bean 对象, 那么就需要用到 BeanPostProcessor, 所以 Spring 在启动过程中就需要做两件事

  • 生成默认的 BeanPostProcessor 对象, 并添加到 BeanFactory 中
    • AutowiredAnnotationBeanPostProcessor, 处理@Autowired, @Value
    • CommonAnnotationBeanPostProcessor, 处理@Resource, @PostConstruct, @PreDestroy
    • ApplicationContextAwareProcessor, 处理 ApplicationContextAware 等回调
  • 找到外部用户所定义的 BeanPostProcessor 对象 (类型为 BeanPostProcessor 的 Bean 对象), 并添加到 BeanFactory 中

new AnnotationConfigApplicationContext

java 复制代码
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
	this();
	register(componentClasses);
	refresh();
}

public AnnotationConfigApplicationContext() {
	// todo 会调用父类的无参构造方法, super(); 创建 BeanFactory (DefaultListableBeanFactory)
	StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
	// new Reader, 用来支持 ApplicationContext 的 register 等功能
	this.reader = new AnnotatedBeanDefinitionReader(this);
	createAnnotatedBeanDefReader.end();
	// new Scanner, 用来支持 ApplicationContext 的 scan 功能
	this.scanner = new ClassPathBeanDefinitionScanner(this);
}

AnnotationConfigApplicationContext

  • 调用父类 GenericApplicationContext 的构造方法, 生成 DefaultListableBeanFactory 并赋值给 this.beanFactory
  • 构造 AnnotatedBeanDefinitionReader, 添加一些基础的 PostProcessor, 为 ApplicationContext 提供 register BeanDefinition 的功能
    • 设置 BeanFactory 的 dependencyComparator 为 AnnotationAwareOrderComparator, 它是一个Comparator, 是用来进行排序的, 会获取某个对象上的 Order 注解或者通过实现 Ordered 接口所定义的值进行排序
    • 设置 BeanFactory 的 autowireCandidateResolver 为 ContextAnnotationAutowireCandidateResolver, 多级继承, 每级提供不同的功能, 如 @Lazy 字段生成代理, @Qualifier 解析, 判断某个 Bean 是否可用于依赖注入 (isAutowireCandidate)
    • 添加 BeanDefinition ConfigurationClassPostProcessor, 是一个 BeanFactoryPostProcessor, 用于解析配置类, 涉及到扫描
    • 添加 BeanDefinition AutowiredAnnotationBeanPostProcessor, 用于处理与 @Autowired, @Value 注解相关的内容, 包括推断构造方法, 依赖注入点查找, 执行注入 等
    • 添加 BeanDefinition CommonAnnotationBeanPostProcessor, 用于处理与 @Resource, @PostConstruct, @PreDestroy 注解相关的内容, 包括依赖注入点查找, 执行依赖注入 等
    • 添加 BeanDefinition EventListenerMethodProcessor, 具体见下方 refresh 中的 registerListeners 阶段, 一个 Bean 中如果有一个方法加了 @EventListener 注解, 将由 EventListenerMethodProcessor 解析处理, 它是一个 BeanFactoryPostProcessor, EventListenerMethodProcessor 实现了 SmartInitializingBean 接口, 当所有非懒加载单例 Bean 创建完后, 会调用实现该接口的 Bean 的 afterSingletonsInstantiated 方法, 方法内, 拿到所有 BeanNames, 遍历调用 processBean 方法, 找到其加了 EventListener 注解的方法, 现在还不能去调用, 默认使用 DefaultEventListenerFactory 将该方法构造成 ApplicationListenerMethodAdapter (实现了 ApplicationListener), 添加到 ApplicationContext 的 listener 中
    • 添加 BeanDefinition DefaultEventListenerFactory, 同上
  • 构造 ClassPathBeanDefinitionScanner, 可以用来扫描得到并注册 BeanDefinition
    • 设置 this.includeFilters = AnnotationTypeFilter(Component.class)
    • 设置 environment
    • 设置 resourceLoader
  • 利用 reader 注册 Application.class 为 BeanDefinition, 类型为 AnnotatedGenericBeanDefinition

ApplicationContext.refresh

java 复制代码
/**
 * Load or refresh the persistent representation of the configuration, which
 * might be from Java-based configuration, an XML file, a properties file, a
 * relational database schema, or some other format.
 * <p>As this is a startup method, it should destroy already created singletons
 * if it fails, to avoid dangling resources. In other words, after invocation
 * of this method, either all or no singletons at all should be instantiated.
 * @throws BeansException if the bean factory could not be initialized
 * @throws IllegalStateException if already initialized and multiple refresh
 * attempts are not supported
 */
void refresh() throws BeansException, IllegalStateException;

这是 ConfigurableApplicationContext 接口上 refresh 方法的注释, 意思是: 加载或刷新持久化的配置, 可能是XML文件, 属性文件, 关系数据库中存储的. 由于这是一个启动方法, 如果失败, 它应该销毁已经创建的单例, 以避免占用资源. 换句话说, 在调用该方法之后, 应该实例化所有的单例, 或者根本不实例化单例

Spring 提供了多种 ApplicationContext, 可刷新的和不可刷新的, 不能刷新是指不能重复刷新, 只能调用一次 refresh 方法, 第二次时会报错

  • AbstractRefreshableApplicationContext, AbstractRefreshableWebApplicationContext, AnnotationConfigWebApplicationContext
  • GenericApplicationContext, AnnotationConfigApplicationContext

底层流程

ConfigurableApplicationContext#refresh, 以 AnnotationConfigApplicationContext 为例

  • prepareRefresh
    • 给子类提供了额外添加 kv 到 Environment 的方式, 检查必要 kv 是否存在, 额外赋了几个值
  • obtainFreshBeanFactory
    • 给子类提供刷新 BeanFactory 的抽象, 由子类决定是否支持, 支持的话, 销毁旧 Bean, 关闭旧 BeanFactory, 重新创建新的 BeanFactory, 返回 BeanFactory
    • SpringMVC / SpringBoot 等可能需要刷新容器, 比如热部署等
  • prepareBeanFactory
    • 设置 BeanFactory 的类加载器
    • 设置 BeanFactory 的表达式解析器, StandardBeanExpressionResolver, 用来解析 SpringEL
    • 添加类型转化注册器, ResourceEditorRegistrar, 自带注册一些默认的 String 转其他对象的转换器
    • 添加 BeanPostProcessor ApplicationContextAwareProcessor, 用来执行 ApplicationContext 相关 Aware 的 Setter 回调方法
    • 添加 ignoredDependencyInterfaces, 忽略指定接口对应 Setter 方法在依赖注入阶段的执行, 因为在依赖注入阶段后还有 Aware 执行阶段也要执行, 否则会执行两次, 没有必要. 比如通过 @Bean(byType/byName) 配置的 Bean, 在依赖注入时会判断实现的接口是否在这个列表中, 在的话就不执行对应 Setter 方法. 而如果给对应 Setter 方法加上 @Autowired 注解则没有此效果, 依赖注入阶段会因 @Autowired 的原因注入一次, 后面的 Aware 阶段又会执行一次
      • AbstractAutowireCapableBeanFactory - autowireByType/autowireByName- unsatisfiedNonSimpleProperties - isExcludedFromDependencyCheck - isSetterDefinedInInterface 里面就会用到 ignoredDependencyInterfaces 这个列表
      • EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware, ApplicationStartupAware
      • BeanNameAware, BeanFactoryAware, BeanClassLoaderAware, 这三个在构造 DefaultListableBeanFactory 的时候添加
    • 添加 resolvableDependencis, 指定某些类型对应的 Bean, 比如要通过 @Autowired 注入一个 ApplicationContext, 我们没有配置这样的 Bean, 但仍然能注入成功, 就是因为这个原因. 在 ByType 依赖注入时, 会先从这个属性中根据类型找 Bean
      • BeanFactory: BeanFactory
      • ResourceLoader: ApplicationContext
      • ApplicationEventPublisher: ApplicationContext
      • ApplicationContext: ApplicationContext
    • 添加 BeanPostProcessor ApplicationListenerDetector, 用于在 Bean 初始化后检测 Bean 是否为 ApplicationListener, 是的话添加到 ApplicationContext 的 listener 中
    • 添加 BeanPostProcessor LoadTimeWeaverAwareProcessor, 负责处理实现 LoadTimeWeaverAware 接口的 Bean 的 Setter 方法的调用
    • 添加一些 Bean 到单例池
      • environment: ApplicationContext 的 Environment
      • systemProperties: 操作系统环境变量, ApplicationContext 的 Environment 中的 SystemProperties
      • systemEnvironment: JVM 环境变量, ApplicationContext 的 Environment 中的 SystemEnvironment
      • applicationStartup: 监控对象
  • postProcessBeanFactory, 模板方法, 子类实现, 补充一些上面通用流程之外的内容, 大多都是和 Web 有关
    • 比如 GenericWebApplicationContext 会补充一些 Web Servlet 相关的内容, 如 BeanPostProcessor, ignoreDependencyInterface, ResolvableDependency, 单例 Bean, request/session/application 作用域等
  • invokeBeanFactoryPostProcessors , 执行BeanFactoryPostProcessor, 会执行 scanner.scan, 将扫描到的 BeanDefinition 注册到 BeanFactory 中
    • 下面单独说
  • registerBeanPostProcessors, 将扫描到的 BeanPostProcessor (比如自己定义的 BeanPostProcessor) 实例化并排序, 并添加到 BeanFactory 的 beanPostProcessors 中, 最后再重新添加一个 ApplicationListenerDetector 对象 (之前其实就添加了过,这里是为了把 ApplicationListenerDetector 移动到最后)
  • initMessageSource, 初始化国际化组件, ApplicationContext 的国际化实现是通过 MessageSource 提供的, MessageSource 通常是我们自己定义的
  • initApplicationEventMulticaster, 初始化事件广播器, 事件广播器是 ApplicationContext 的事件广播实现, 通常是我们自己定义的
    • ApplicationContext.publishEvent("111") 底层就是通过 ApplicationEventMulticaster.multicastEvent 实现的
    • 发布的事件分 ApplicationEvent 和 PayloadApplicationEvent, 自定义的消息在监听到后需要转换为 PayloadApplicationEvent 才能看到具体内容
  • onRefresh, 模板方法, 子类实现, 给子类提供的一个 Refresh 回调
  • registerListeners, 将扫描到的 ApplicationListener (比如自己定义的事件监听器) 添加到 ApplicationEventMulticaster 中, 便于事件发布时能通知到对应监听器. 因为这时 FactoryBean 还没有调用 getObject 方法生成 Bean 对象, 所以这里要再根据类型找一下 ApplicationListener, 记录一下对应的 beanName
    • 注册监听器有多种方式, 如 Bean 实现 ApplicationListener 接口, 或 方法添加 ApplicationEvent 参数, 添加 @EventListener 注解
    • 一个 Bean 如果实现了 ApplicationListener 接口, 在初始化后阶段, 将由 ApplicationListenerDetector 这个 BeanPostProcessor 识别并加入到 ApplicationContext 的 listener 中. 即使这个 Bean 是懒加载的也没有关系(虽然实例化全部非懒加载 Bean 的流程在这一步后面), 因为在往事件多播器中注册的时候, 会对监听器执行 getBean, 懒加载的也会被创建出来.
      • ApplicationListenerDetector, 在前面 refresh 的 prepareBeanFactory 阶段添加到 beanPostProcessors 中
    • 一个 Bean 中如果有一个方法加了 @EventListener 注解, 将由 EventListenerMethodProcessor 解析处理, 它是一个 BeanFactoryPostProcessor, EventListenerMethodProcessor 实现了 SmartInitializingBean 接口, 当所有非懒加载单例 Bean 创建完后, 会调用实现该接口的 Bean 的 afterSingletonsInstantiated 方法, 方法内, 拿到所有 BeanNames, 遍历调用 processBean 方法, 找到其加了 EventListener 注解的方法, 现在还不能去调用. 默认使用 DefaultEventListenerFactory 将该方法构造成 ApplicationListenerMethodAdapter (实现了 ApplicationListener), 添加到 ApplicationContext 的 listener 中
      • EventListenerMethodProcessor, 在 new ApplicationConfigApplicationContext 初始化 Reader 的时候, 就会添加成为 BeanDefinition
      • DefaultEventListenerFactory, 在 new ApplicationConfigApplicationContext 初始化 Reader 的时候, 就会添加成为 BeanDefinition
  • finishBeanFactoryInitialization, 实例化所有非懒加载的单例 Bean
  • finishRefresh, 完成刷新
    • 初始化一个 LifecycleProcessor, 不存在就用 DefaultLifecycleProcessor
      • Spring 容器也有生命周期的概念, 比如一个 Bean 实现了 SmartLifecycle, 就可以覆盖 start / stop 等方法来监听容器的状态
      • finishRefresh 中调用 start, ApplicationContext.close() 时调用 stop, isRunning 返回 false 才会调用 start, 返回 true 才会调用 stop
    • 调用 lifecycleProcessor 的 onRefresh 方法, 如果是 DefaultLifecycleProcessor, 那么会获取所有类型为 Lifecycle 的 Bean 对象, 然后调用它的 start 方法, 这就是 ApplicationContext 的生命周期扩展机制
    • 发布刷新完成事件 ContextRefreshedEvent

refresh - invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors 阶段, 会调用所有 BeanFactoryPostProcessor 的方法, 这个阶段在创建非懒加载单例 Bean 的 finishBeanFactoryInitialization 阶段之前, 所以此阶段对 BeanDefinition 的修改是有效的

BeanFactoryPostProcessor

BeanPostProcessor 用于操作 Bean, 即方法入参都是一个 Bean

BeanFactoryPostProcessor 与之类似, 只不过是用于操作 BeanFactory, 只提供了一个方法 postProcessBeanFactory, 方法入参是一个 ConfigurableListableBeanFactory, 这个工厂不支持注册 BeanDefinition, 但是能获取 BeanDefinition, 然后修改其内容

BeanDefinitionRegistryPostProcessor 是 BeanFactoryPostProcessor 的子接口, 额外提供了一个方法 postProcessBeanDefinitionRegistry, 入参是一个 BeanDefinitionRegistry, 这个方法支持注册 BeanDefinition

我们说的扫描 BeanDefinition, 其实就是基于 BeanDefinitionRegistryPostProcessor 接口实现的, 具体的类叫 ConfigurationClassPostProcessor

postProcessBeanDefinitionRegistry 会早于 postProcessBeanFactory 执行

相关推荐
熊大如如5 小时前
Java 反射
java·开发语言
猿来入此小猿5 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
goTsHgo6 小时前
Spring Boot 自动装配原理详解
java·spring boot
卑微的Coder6 小时前
JMeter同步定时器 模拟多用户并发访问场景
java·jmeter·压力测试
pjx9876 小时前
微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
java·spring cloud·微服务·eureka
炒空心菜菜6 小时前
SparkSQL 连接 MySQL 并添加新数据:实战指南
大数据·开发语言·数据库·后端·mysql·spark
多多*6 小时前
算法竞赛相关 Java 二分模版
java·开发语言·数据结构·数据库·sql·算法·oracle
爱喝酸奶的桃酥6 小时前
MYSQL数据库集群高可用和数据监控平台
java·数据库·mysql
唐僧洗头爱飘柔95277 小时前
【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析
java·spring·mybatis·springmvc·动态代理·ioc容器·视图控制器
骑牛小道士7 小时前
Java基础 集合框架 Collection接口和抽象类AbstractCollection
java