GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • 卡码笔记-最强八股文
  • 计算机基础
  • Python
  • C++
  • Java
  • Go
  • ChatGPT充值
  • Claude充值
  • 国内使用Claude
  • 中转站推荐
  • 🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经

This view

  • Original page
  • New address

GeezerVison is showing notes.kamacoder.com — Bean生命周期|大厂面试题|Java高频面试题|Spring、BeanPostProcessor、循环依赖、三级缓存

# Bean生命周期

# 简要回答

  • Bean的生命周期可以概括为容器初始化、Bean实例化、依赖注入、初始化、使用和销毁阶段,由Spring容器进行管理,通过注解、配置文件或接口进行配置管理。

# 详细回答

  1. 在容器初始化阶段,Bean容器通过XML或注解扫描Spring Bean的定义,将其封装成BeanDefinition对象并注册到BeanFactory中。
  2. 在实例化阶段中,容器会通过构造器反射创建Bean实例。
  3. 在依赖注入阶段中,容器通过Autowired、Resource或者XML配置将Bean实例的属性值或者引用注入到其他Bean中。
  4. 在Bean初始化阶段:
    • 容器会检查Aware相关的接口:如果Bean实现了BeanNameAware接口,调用setBeanName方法,传入Bean的名字;如果Bean实现了BeanFactoryAware接口,调用setBeanFactory方法,传入BeanFactory实例;如果Bean实现了ApplicationContextAware接口,调用setApplicationContext方法,注入ApplicationContext实例。
    • 执行前置处理:如果Bean实现了BeanPostProcessor接口,Spring会调用它们的postProcessBeforeInitialization()方法。
    • 执行自定义初始化方法,调用Bean使用@PostConstruct或XML方式init-method声明的初始化方法,如果Bean实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法;
    • 执行后置处理:如果Bean实现了BeanPostProcessor接口,Spring就调用他们的postProcessAfterInitialization()方法。
  5. Bean在初始化后就可以被应用程序使用,使用结束后进行销毁,执行@PreDestroy标注或者在XML中使用destroy-method指定的方法,如果Bean实现了DisposableBean接口,Spring会调用destroy()方法。

# 知识图解

  • Bean的生命周期示意图 image

# 知识扩展

  1. 面试官可能追问
  • Q1:Bean的作用域对生命周期有什么影响?
    • 作用域为 单例(singleton) 时,Bean由容器管理完整的生命周期,在初始化后存入容器缓存,容器关闭时销毁。
    • 作用域为原型(prototype) 时,容器仅负责实例化、依赖注入和初始化阶段,后续容器不会主动调用,销毁阶段由用户手动处理或JVM垃圾回收处理。
    • 其他作用域如request、session、global session等生命周期与作用域一致,随着请求创建,请求结束销毁。
  • Q2:@PostConstruct、InitializingBean、init-method有没有执行顺序,为什么?
    • 先执行@PostConstruct,再执行InitializingBean,然后执行init-method。
    • @PostConstruct是由Spring的CommonAnnotationBeanPostProcessor解析,属于BeanPostProcessor前置处理后的回调;
    • InitializingBean是Spring内置接口,容器直接调用其方法,优先级高于自定义XML配置;
    • init-method是XML配置的自定义方法,优先级最低
  • Q3:Spring怎么解决单例Bean的循环依赖问题?为什么原型Bean无法解决?
    • Spring是通过三级缓存来解决循环依赖问题的。一级缓存SingletonObjects存储完全初始化好的Bean,二级缓存EarlySingletonObjects存储早期的Bean引用,是已经实例化但还未完全初始化的Bean,三级缓存SingletonFactories存储Bean的工厂,可以生成早期Bean引用。
    • 假设A和B存在循环依赖问题,A创建实例后未注入属性时会存放ObjectFactory对象到三级缓存中,开始给A注入属性时发现A依赖B,此时容器开始创建B,B实例化后也会被存放ObjectFactory对象到三级缓存中,Spring给B注入属性时发现B依赖A,容器在三级缓存中找到A的ObjectFactory对象,获取A的早期引用并放入二级缓存,并清理三级缓存。将A的早期引用注入到B中,完成B的初始化后进入一级缓存。回到A的属性注入环节,将就绪的B注入A,完成A的初始化后进入一级缓存,解决循环依赖问题。
    • 原型Bean无法解决循环依赖问题,因为原型Bean每次获取都会创建新实例,会导致递归创建,Spring直接抛出BeanCurrentlyInCreationException异常。
  • Q4:如何监听Bean的生命周期?
    • 实现BeanPostProcessor接口,在postProcessBeforeInitialization和postProcessAfterInitialization方法中添加监听逻辑。
    • Bean实现Aware接口、InitializingBean接口、DisposableBean接口,在初始化、销毁前、销毁后添加监听逻辑。
    • 使用@EventListener注解监听容器事件,如ContextRefreshedEvent容器初始化完成、ContextClosedEvent容器关闭等。

← Bean的作用域? 23种设计模式实战课 →

评论

验证登录状态...

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.