JVM + IOC + Bean 完整总结
一、JVM(JDK8+,重点内存区域)
元空间 Metaspace:存类的字节码、Class 元信息、常量池。
类加载成功后,Class 信息放这里;一个类加载器下,同一个 Class 只会加载一次。
类加载触发时机:实例化 Bean 那一刻才加载 Class,扫描阶段不加载 Class。
堆 Heap:所有 Java 对象实例存放的地方。
BeanDefinition 对象、Bean 实例 (target 原始对象 /proxy 代理对象)、BeanDefinitionMap、singletonObjects(ConcurrentHashMap)全部在堆。
Map 里只存对象引用(内存地址),不是对象实体。
虚拟机栈:每个线程私有。
- 方法内局部变量(基本类型、对象引用地址)放在栈帧;方法执行完毕,栈帧出栈销毁。
程序计数器:线程私有,记录当前线程执行到哪一行字节码。
本地方法栈:给 native 本地方法使用。
直接内存:堆外内存,不归 GC 管理。
GC 规则:堆里的对象,没有强引用时会被 GC;元空间的 Class 很难被回收。
二、IOC 容器(Spring 核心思想:控制反转)
IOC 是思想;BeanFactory/ApplicationContext是 IOC 容器的实现(容器本身也是堆上的 Java 对象)。 容器内部两个核心 Map:
BeanDefinitionMap(元数据核心)
key:bean 名称;value:
BeanDefinition对象(堆中的模板对象)启动包扫描阶段生成,保存所有 Bean 的描述模板:类名、作用域 scope、是否懒加载等。
作用:告诉 Spring如何创建 Bean。
singletonObjects 单例池
本质:
ConcurrentHashMap,堆内存。key:bean 名称;value:已经实例化完成的单例 Bean 的对象引用。
作用:缓存建好的单例 Bean,后续 getBean 直接复用,避免重复创建。
prototype 多例 Bean不会放入单例池。
IOC 容器的核心动作:依赖注入 DI,容器自动给 Bean 的成员变量赋值,不用手动 new 对象。
三、Bean 以及 3 种常见作用域
基础概念
- BeanDefinition:模板对象(堆),不是业务 Bean 实例;描述 Bean 信息。
- target:原始业务对象(堆),没有 AOP 增强。
- proxy:AOP 动态生成的代理对象(堆)。
- 需要 AOP 增强时,放入单例池的是 proxy 的引用;proxy 内部持有 target 的引用,target 不进单例池。
- 成员变量:属于 Bean 对象的字段,存在堆上的 Bean 实例中。
作用域
singleton 默认单例(非懒加载)
容器启动:扫描生成 BeanDefinition 存入 BeanDefinitionMap,立刻实例化 Bean。
实例化触发类加载,Class 放入元空间;实例创建完成放入 singletonObjects。
单例池持有强引用,容器不关闭,不会 GC;容器关闭才释放引用。
经典坑:单例 Bean 注入 prototype 多例 Bean:依赖注入只在单例实例化的时候执行一次,后续调用方法复用同一个 prototype 对象,不会自动新建。
singleton + @Lazy 懒加载单例
容器启动:只生成 BeanDefinition,不实例化、不加载 Class。
第一次 getBean(使用时),才实例化 Bean,触发类加载,创建对象放入单例池;后续复用。
prototype 多例 @Scope (“prototype”)
容器启动:只生成一份 BeanDefinition 模板存入 BeanDefinitionMap。
每次调用 getBean,拿同一份模板新建全新 Bean 实例,不存入单例池。
Spring 创建完 prototype 实例后不再持有引用;没有引用时,对象会被 GC。
Spring不会执行 prototype 的 @PreDestroy 销毁回调。
getBean 通用流程
- 优先去 singletonObjects 单例池查找,找到直接返回 Bean 引用;
- 单例池没有 → 去 BeanDefinitionMap 取出对应的 BeanDefinition 模板;
- 根据模板的类名,触发类加载,Class 信息载入元空间;
- 反射实例化 Bean 对象,执行依赖注入;
- 判断是否需要 AOP 增强,需要则生成 proxy 代理对象;
- 如果是 singleton,放入 singletonObjects;prototype 不放入;
- 返回对象引用。
四、整合笔记完整版(可直接复制背诵)
【JVM】 元空间存类字节码Class信息;堆存放所有对象实例;虚拟机栈存放方法局部变量,方法结束销毁。 类加载时机:实例化Bean那一刻才加载Class,扫描BeanDefinition阶段不会加载Class;同一个Class只会加载一次。 【IOC容器】 IOC是控制反转思想;BeanFactory/ApplicationContext是IOC容器实现(堆上对象)。 BeanDefinitionMap是IOC元数据核心,存放所有Bean的BeanDefinition模板对象; singletonObjects单例池本质是堆中的ConcurrentHashMap,存放实例化完成的单例Bean引用。 Map中存储的是对象引用地址,不是对象实体。 依赖注入DI:容器自动给Bean的成员变量赋值,成员变量保存在堆上的Bean实例中。 【Bean & AOP】 BeanDefinition是元信息模板对象(堆),不是业务Bean实例。 target:原始业务对象;proxy:AOP代理对象;AOP场景下单例池存放proxy引用,proxy内部持有target,target不进单例池。 Bean作用域: 1.singleton(默认):启动就实例化,放入单例池;容器存活期间强引用,不会GC。 2.singleton+@Lazy:启动只存BeanDefinition,第一次getBean才实例化、加载Class。 3.prototype多例:BeanDefinition全局只有一份;每次getBean新建堆对象,不进单例池;Spring不管理销毁。 重要坑点:单例Bean注入prototype,仅在单例实例化阶段注入一次,后续调用复用同一个prototype对象,不会自动新建。 getBean流程:优先从单例池查找;没有则读取BeanDefinition模板,触发类加载、实例化、DI、AOP代理创建;singleton存入单例池,prototype不存入。