Spring八股

Spring

refresh创建IOC容器

Spring 容器启动时会创建IOC容器,在创建容器时,会调用 refresh()方法,整个容器就是通过该方法,完成所有的 bean 的创建以及初始化

重要的类/对象

  • ClassPathXmlApplicationContext:使用配置文件的容器
  • AnnotationConfigApplicationContext:使用配置类的容器
  • BeanDefinition:Bean的相关信息。如是否是单例的,Bean的类型,是否是懒加载,依赖哪些类,自动装配的模型
  • beanDefinitionMap:存放bean对应的BeanDefinition
  • beanDefinitionNames:存放所有bean的名字
  • BeanFactoryPostProcessor:BeanFactory的后置处理器
  • BeanPostProcessor:Bean的后置处理器,通过它可以实现AOP、Bean的创建

重要步骤

BeanFactory初始化

invokeBeanFactoryPostProcessors()会执行所有BeanFactoryPostProcessor

  • Spring内置的BeanFactory后处理器:ConfigurationClassPostProcessor,会解析出所有交由Spring管理的Bean并解析成BeanDefinition
  • 自定义的BeanFactory后处理器:实现了BeanFactoryPostProcessor接口或BeanDefinitionRegistryPostProcessor接口。会先执行后者的实现类

准备上下文

registerBeanPostProcessors()会找到并实例化所有的BeanPostProcessor,并放到beanPostProcessors集合中

finishBeanFactoryInitialization()完成了所有非懒加载的单例Bean的实例化和初始化,属性的填充以及解决了循环依赖等问题

12个步骤

概览

  • 1:准备工作
  • 2~6:创建准备BeanFactory的各项功能
  • 7~12:准备ApplicationContext

1.prepareRefresh()-开启容器,加载键值

  • 创建和准备了Environment对象

  • Environment对象的作用:加载了一些键值信息:

    • jvm提供的键值
    • 操作系统系统里的键值
    • 配置文件里提供的键值信息
  • Environment的作用之一是为后续@Value注入值的时候提供信息

2.obtainFreshBeanFactory()-获取或创建Bean工厂

  • 创建了BeanFactory对象

  • BeanDefinitionMap为BeanFactory的成员对象,存储了BeanDefinition

    • BeanDefinition作为bean的设计蓝图,规定了bean的特征,如单例多例、依赖关系、初始化销毁方法等
    • BeanDefinition的来源可以通过xml获取、配置类获得、组件扫描或编程添加等
  • BeanFactory的作用是负责bean的创建、依赖注入和初始化

3.prepareBeanFactory()-完善Bean工厂

  • 创建用来解析SpEL的beanExpressionResolver

  • 创建执行类型转换的propertyEditorRegistrars

  • 创建特殊bean注入的resolvableDependencies

  • 扩展bean的创建功能的beanPostProcessors

  • StandardBeanExpressionResolver来解析SpEL

  • ResourceEditorRegister会注释类型转换器,并应用ApplicationContext提供的Environment来完成${}解析

  • 特殊bean指beanFactory以及ApplicationContext,通过registerResolvableDependency来注册它们

4.postProcessBeanFactory()-子类扩展Bean工厂

  • 后处理可以理解为添加功能。
  • 默认为空实现,留个子类扩展
  • 一般Web环境的ApplicationContext都要利用它注册新的Scope,完善Web下的BeanFactory

5.invokeBeanFactoryPostProcessors()-后处理器扩展Bean工厂

  • 预先定义好的后处理,通过处理器的方式添加BeanFactory的功能
  • 后置处理器可以扩展beanFactory的功能,用来补充和修改BeanDefinition
  • ConfigurationClassPostProcessor-解析@Configuration、@Bean、@Import等

6.registerBeanPostProcessors()-注册Bean后处理器

  • bean后后处理器充当bean的扩展点,可以工作在bean的实例化、依赖注入、初始化阶段
  • 如有解析@Autowired、@Value、@Resource等注解的后处理器

7.initMessageSource()-国际化

  • 初始化messageSource,用来做国际化功能

8.initApplicationEventMulticaster()-初始化事件多播器

  • 这个类会持有所有的事件监听器(ApplicationListener),当有ApplicationEvent事件发布时,该事件监听器能根据事件类型,检索到对该事件感兴趣的ApplicationListener

9.onRefresh()-初始化子容器中的bean

  • 执行其他的初始化操作,例如和SpringMVC整合时,需要初始化一些其他的bean,但是对于纯Spring工程来说,onRefresh()方法是一个空方法。

10.registerListeners()-注册监听器

  • 接收事件

11.finishBeanFactoryInitialization()- 初始化所有剩下的单例 bean

  • conversionService也是一套转换机制,作为对PropertyEditor的补充
  • 内嵌值解析器用来解析@Value中的${},借用的是Environment的功能
  • 单例池用来缓存所有单例对象
  • 对象创建分为三个阶段:创建、依赖注入、初始化,每个阶段都有不同的bean处理器参与扩展

12.finishRefresh()-准备声明周期管理器,发布ContextRefresh事件

  • lifecycleProcessor用来控制容器内需要生命周期管理的bean

Bean的作用域

  • Singleton:默认,在IOC容器中只有一个实例
  • Prototype:可以有多个实例
  • Request:每次http请求都会创建一个Bean
  • Session:一个Session中对应一个Bean对应一个实例
  • Global-session:全局Session中,一个Bean对应一个实例

Bean的生命周期

7个阶段

Bean为懒惰初始化,生命周期从doGetBean()方法开始

概览

  • 阶段1:处理名称,检查缓存
  • 阶段2:检查父工厂
  • 阶段3:检查DependsOn
  • 阶段4:按Scope创建bean
  • 阶段5:创建bean
  • 阶段6:类型转换
  • 阶段7:销毁bean

阶段1

  • 先把别名解析为实际名称,再进行后续处理
  • 若要FactoryBean本身,需要使用&名称获取
  • 检查缓存里是否有:
    • 一级缓存是singletonObjects,放单例成品对象
    • 二级缓存是earlySingletonObjects,放单例工厂的产品,可称为提前单例对象
    • 三级缓存是singletonFactories,放单例工厂

阶段2

  • 缓存中没有bean回去父容器中找
  • 父容器中的bean和子容器中的bean名称可以重复

阶段3

  • 如果A显式依赖于B,则B会被先创建
  • DependsOn用在非显式依赖的bean的创建顺序控制

阶段4

  • 常见scope:
    • singleton scope表示从单例池范围内获取bean
      • 容器创建时创建,容器销毁时销毁
    • prototype scope表示从不缓存bean,每次创建新的
      • 用时创建,不用时手动销毁
    • request scope表示从request对象范围内获取bean
      • 在request域中创建,request销毁时销毁

阶段5

  • 创建阶段:
    • AutowiredAnnotationBeanPostProcessor选择构造:优先使用带@Autowired的构造方法来创建bean,如果只有一个有参构造,则用这个有参构造创建bean
    • 默认构造:保底使用无参构造来创建
  • 依赖注入阶段:
    • 后处理器扩展功能:按注解匹配要注入的bean
    • 根据名字、类型去容器中找bean
    • xml精确指定bean
  • 初始化阶段:
    • 处理Aware接口,如BeanNameAware、BeanFactoryAware,BeanFactory会把相应的资源传递进来
    • 调用初始化方法,初始化方法定义有@PostConstruct、实现InitalizingBean接口等
    • 创建aop代理
  • 注册可销毁bean
    • 将有销毁方法的bean保存起来,销毁时调用方法

阶段6

  • 如果getBean的requiredType参数与实际得到的对象类型不同,会尝试类型转换

阶段7

  • 根据scpoe来销毁bean

事务的传播行为

级别 描述
Required(默认) 支持当前事务,没有事务会创建一个
Supports 支持当前事务,没有事务则以非事务的方式执行
Mandatory 支持当前事务,没有事务会抛出异常
Requires_new 创建新事务并挂起当前事务
Not_supported 以非事务方式执行,会挂起当前事务
Never 以非事务方式执行,有事务会抛出异常
Nested 嵌套事务

事务失效场景

场景1:检查异常

需要try..catchthrow的异常都是检查异常

运行时异常是非检查异常

抛出检查异常导致事务不能正常回滚

原因:spring默认只会回滚非检查异常

解决方式:在注解上加上@Transactional(rollbackFor=Exception.class)设置需要回滚的异常

场景2:错误try catch

原因:事务是通过代理实现的,如果在被代理方法内catch了异常,外层调用者是不知道发生了异常的,从而事务失效

解决方式1:把异常抛出去

解决方式2:手动设置事务状态TransactionStatus.setRollbackOnly()

场景3:aop切面顺序不对

原因:在自定义切面里catch了异常,导致更上层的事务切面不知道发生了异常

解决方式1:同场景2

解决方式2:使自定义切面优先级比事务的高@Order(Ordered.LOWEST.PRECEDENCE - 1)

场景4:加在非公共方法上

原因:Spring为方法创建代理、添加事务通知、前提条件都是方法是public的

场景5:父子容器导致的事务失效

原因:子容器扫描范围过大,把未加事务配置的service扫描进来

解决方式1:容器各自扫各自的包

解决方式2:不用父子容器

场景6:调用本类方法导致传播行为失效

原因:本类方法调用没有经过代理增强

解决方式:依赖注入自身

场景7:锁失效

原因:@Transactional没有保证原子行为,在方法上加锁只能保证方法内的原子性,提交事务时锁失效

解决方式1:synchronized范围扩大至代理方法调用

解决方式2:sql语句select ... for update替换select

SpringMVC执行流程

  1. 初始化阶段

    • 第一次用到DispatcherServlet时,会创建其对象并执行init方法
    • 容器初始化后,会将初始化好的重要组件赋值给DispatcherServlet的成员变量

  2. 匹配阶段

    • 用户请求到达DispatcherServlet,由其遍历所有的HandlerMapping,找到与路径匹配的处理器
    • 将HandlerMethod连同匹配到的拦截器,生成调用链对象返回
    • 遍历HandlerAdapter,找到能处理HandlerMethod的适配器,开始调用

  3. 执行阶段

    • 执行拦截器的preHandle
    • 调用HandlerMethod,返回ModelAndView
    • 执行拦截器的postHandle
    • 解析ModelAndView
    • 执行拦截器的afterCompletion

注解

Spring常见注解

SpringMVC常见注解

SpringBoot常见注解

SpringBoot自动配置

@SpringBootApplication主要由三个注解构成

  • @SpringBootConfiguration
    • @Configuration可以多个,@SpringBootConfiguration只能一个,用于表示当前类为SpringBoot配置类
  • @EnableAutoConfiguration
    • @AutoConfigurationPackage:记录标注了这个注解的包名
    • @Import(AutoConfigurationImportSelector.class):导入自动配置相关的bean,加载META-INF/spring.factories中的配置类
  • @ComponentScan
    • 属性excludeFilters用于排除一些类不注册为bean

循环依赖

切面

通过代理对象来关联ProxyFactory实现切面,SpringBoot通过自动代理后处理器来识别相关注解

术语

  • Advisor:最基础的切面,把一个Advice和一个Pointcut组合起来

  • Advice:增强

  • Pointcut:切点

  • Aspect:切面

  1. 最基本的切面是Advisor,一个Aspect切面对应一到多个Advisor

  2. 最基本的Advice是MethodInterceptor,其他Advice最终都会适配为MethodInterceptor

  3. 创建代理的方式有:实现了用户自定义接口,采用jdk动态代理;没有实现用户自定义接口,采用cglib代理;设置了setProxyTargetClass(True),统一采用cglib代理

  4. 切面、切点、通知等都不会被代理

  5. 自动代理后处理器调用时机:创建阶段、依赖注入阶段初始化阶段

注解

  • @Aspect:表示为切面类
  • @Around、@Before、@After等:通知方法,可以加切点表达式

三级缓存

作用

  • 一级缓存作用:限制bean在beanFactory中只存一份

只有一级缓存不能解决循环依赖问题

  • 二级缓存作用(Spring中的三级缓存):存还未装载成员变量的空对象,解决循环依赖,在初始化完后把二级缓存中的空对象清除掉

    二级缓存不能解决循环依赖中有代理的情况

  • 三级缓存作用(Spring中的二级缓存):解决循环依赖中代理创建过晚的问题,通过工厂判断是否需要代理,需要则提前创建代理对象,否则返回本身空对象

    三级缓存不能解决构造函数中有循环依赖:构造不出来,无法放到缓存中

    解决方式1:加@Lazy注解,会先创建代理对象注入,待用到时再注入

    解决方式2:通过ObjectFactory<B> b 来先注入工厂,使用时在创建bean

单例Bean是线程安全的吗

不是线程安全的。@Scope注解默认是sington单例的。如果spring的bean中注入的都是无状态的对象,是没有线程安全问题的,如果在bean中定义了可以修改的成员变量,是要考虑线程安全问题的,可以使用多例或加锁来解决问题

AOP

面向切面编程,用于将那些与业务无关,但对多个对象产生影响的公共行为或逻辑,抽出并封装成一个可重用的模块

常见AOP使用场景

  • 记录操作日志

  • 缓存处理

  • 事务

    编程式事务:使用TransactionTemplate,对代码有侵入性

    声明式事务:使用@Transactional注解,通过AOP功能,对方法进行拦截

自动装配

@SpringBootApplication中包含的@EnableAutoConfiguration中用@Import导入了配置选择器

内部读取了该项目和引用的Jar包的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名,根据这些配置类中定义的Bean所指定的条件来决定是否注入到Spring容器中


Spring八股
http://xwww12.github.io/2026/07/30/八股/Spring八股/
作者
xw
发布于
2026年7月30日
许可协议