1. Bean的生命周期
实例化 -> 依赖注入 -> 初始化 -> 销毁
回答就说分成这四步。
重点是,
在第二步完成依赖注入,
在第三步里面完成AOP。即AOP代理是在【初始化】【后置处理阶段】织入。
这里通常有八股文的问题:
第一步中 通过反射创建对象,
第三步中 aop通过JDK动态代理或CGLIB动态代理创建对象,
这三者有什么区别和联系?
容器启动
│
▼
读取配置(XML/注解/JavaConfig)
│
▼
定位 Bean 定义(BeanDefinition)
│
▼
实例化 Bean(反射)
│ └── 使用 Class.forName() + Constructor.newInstance()
│
▼
属性填充(依赖注入)
│ └── 通过反射设置 @Autowired / @Resource 等字段
│
▼
Aware 回调(可选)
│ └── BeanNameAware, ApplicationContextAware 等
│
▼
BeanPostProcessor 前置处理
│ └── postProcessBeforeInitialization()
│
▼
初始化(init-method / afterPropertiesSet)
│
▼
BeanPostProcessor 后置处理
│ └── ★ AOP 在这里织入增强逻辑
│ ├─ 如果有接口 → JDK 动态代理
│ └─ 如果没有接口 → CGLIB 代理
│
▼
得到最终 Bean(可能是代理对象)
│
▼
放入容器,交给应用使用
│
▼
容器关闭 → 调用 destroy() / destroy-method()
2. Bean的作用域
Spring 定义了多种作用域(Scope),控制 Bean 的 生命周期范围:
singleton(默认)
容器中只有一个实例(全局单例)。
适合无状态 Bean(如 Service、DAO)。
线程安全要自己保证。
prototype(原型)
每次获取 Bean 都会新建一个实例。
适合有状态 Bean(如带临时数据的对象)。
Spring 只负责创建,不负责销毁。
request(Web 环境)
每个 HTTP 请求创建一个 Bean,随请求结束而销毁。
适合请求级别的数据处理。
session(Web 环境)
每个 HTTP Session 创建一个 Bean,随 Session 结束而销毁。
适合用户会话级别的数据。
application(Web 环境)
基于 ServletContext 的全局作用域,相当于一个 Web 应用只有一个实例。
websocket(Web 环境)
每个 WebSocket 连接对应一个 Bean。
面试高频问题:
单例 Bean 是线程安全的吗?Spring 不保证线程安全,需自己处理(加锁、ThreadLocal)。
原型 Bean 的销毁方法会调用吗?默认不会,Spring 不负责 prototype Bean 的销毁,需要手动管理。
循环依赖是在哪个阶段解决的?在 属性注入阶段,通过 三级缓存 提前暴露代理对象。
所以啊,那么多作用域,记住两个就行。单例作用域和原型作用域。然后是单例作用域自己保证线程安全,原型作用域自己手动销毁。然后是循环依赖的问题。就这三个问题。
--
修改:PlutoKey FROM 223.104.83.*
FROM 223.104.83.*