一、写在开头
简单记录下来时路,以后也能回头看看鼓励下自己。我以前不喜欢拍照,觉得没什么意思,有一天百度云盘给我推不知道什么时候从相册推到百度云相册的照片,那是我口罩时期在家上体育课的照片,我现在回头望过去觉得那时很幸福。现在后悔以前没怎么拍照片,想回忆起过去只能靠脑袋里的记忆,但随着时间是越来越模糊。
说多了,现在开始记录spring源码的学习过程吧
二、正式开始
2025年5月7日00:07:27
🌱 初识 Spring:为什么我们需要它?
在早期开发 Java 企业级应用时,程序员需要手动处理很多琐碎的事情,比如:
- 对象的创建和管理(谁来 new?谁来管理生命周期?)
- 多个模块之间的依赖关系如何连接?
- 业务逻辑和日志、权限控制等“杂事”混杂在一起,维护难度很高
于是,Spring 框架就登场了。它就像一个万能工具箱,为我们解决了这些问题,让开发工作更简单、高效。
🧰 Spring 能做什么?简单点说就是这几点:
- 帮你管理对象(Bean):你不需要自己去创建、管理对象,Spring 会代劳。
- 解耦合:模块之间不再直接依赖,而是通过 Spring 容器连接,改起来更灵活。
- 提供事务、消息、远程调用等强大功能:而且整合了主流框架(如 MyBatis、JPA)。
- 可以像切洋葱一样“切”功能:用 AOP 把权限、日志、监控从业务逻辑中分离。
- 开放灵活:你可以只用 Spring 的一部分,不需要全盘接入。
🔧 Spring 的核心理念:IOC 与 AOP
🧩 IOC(控制反转)
简单理解:你不再负责 new 对象,Spring 来做这事。
以前你这样写代码:
UserService service = new UserServiceImpl();
现在你只要告诉 Spring:“我要个 UserService”,Spring 会自动帮你创建、配置好:
@Autowired
private UserService userService;
这就是依赖注入(DI),是 IOC 的一种实现方式。
🪚 AOP(面向切面编程)
比如你有这样的代码:
public void placeOrder() {
log();
checkPermission();
doBusinessLogic();
}
这些日志、权限和真正的业务混在一起,不好维护。
用 AOP,你可以把“日志”“权限”这些通用功能“切出去”:
@Log
@CheckPermission
public void placeOrder() {
doBusinessLogic();
}
🏗️ Spring 的结构是怎样的?
你可以把 Spring 看作一座大楼,每一层都负责不同的工作,从基础设施到高级服务。
第1层:核心容器 Core Container(基础设施层)
这是 Spring 的地基,负责“管理对象”这件事:
- spring-core:IOC/DI 的核心实现
- spring-beans:负责读取配置、管理 Bean 的生命周期
- spring-context:提供类似“应用上下文”的功能,像是 Spring 的运行环境
- spring-expression:可以写复杂表达式动态操作对象(比如
#{user.age > 18}
)
第2层:数据访问层(JDBC、ORM 等)
用于操作数据库:
- spring-jdbc:简化传统 JDBC 编程(不用再写 try-catch-finally)
- spring-orm:整合 JPA、Hibernate、MyBatis 等 ORM 框架
- spring-tx(事务):帮你自动管理事务(不用自己写 commit/rollback)
第3层:Web 支持(Servlet、MVC、WebSocket 等)
- spring-web:支持 Web 项目、文件上传、IoC 初始化
- spring-webmvc:核心的 MVC 实现,适合开发 REST API 或传统 Web 应用
- spring-websocket:支持实时双向通信(聊天、直播场景)
- spring-portlet:为基于 Portlet 的环境提供支持(较少使用)
第4层:切面编程与工具层
- spring-aop:支持定义切面、切点和通知
- spring-aspects:整合 AspectJ 框架(AOP 更强大)
- spring-instrument:用于类加载优化(主要用于服务器部署)
- spring-messaging:消息协议支持(如 STOMP + WebSocket)
第5层:测试支持
- spring-test:方便用 JUnit 或 TestNG 测试 Spring 应用
🧱 总结一句话:
Spring 是一个分层、模块化的“开发大工厂”,核心是 用容器管理对象(IOC),并通过 切面编程(AOP)实现对业务代码的“功能增强”。你可以只用你需要的那部分,逐步深入。
2025年5月7日23:58:22
非常好!你已经一步步掌握了 Spring 中 Bean 实例化的各种方式,现在我来帮你用通俗、连贯的方式,整理成一份 从开始到结束的 Spring Bean 实例化学习笔记,让你不仅懂**“怎么创建”,更清楚“什么时候创建”、“为什么这么设计”**。
🧭 Spring Bean 实例化全流程学习笔记(通俗版)
🌱 一、Spring 到底怎么帮我们创建对象?
在 Spring 框架中,你定义的每一个类,想要交给 Spring 管理,它就会变成一个 Bean。
什么是 Bean?
Bean 是被 Spring 容器管理的对象,它的创建、初始化、依赖注入、销毁等都由 Spring 控制。
🧩 二、Spring 创建 Bean 的流程大致分为两个阶段:
1️⃣ 注册阶段:告诉 Spring 要管理什么
“我有个类叫
UserService
,请你帮我记住它的结构、怎么创建它”
你可以用几种方式来完成这个注册过程:
- 用注解:
@Component
,@Configuration
,@Bean
等等 - 用 XML 配置
<bean>
- 用 Java API:
registerBeanDefinition(...)
👉 核心机制是: 所有的这些方式,最终都会创建一个 BeanDefinition
,这是 Spring 用来描述 Bean 的“说明书”。
2️⃣ 实例化阶段:Spring 真的去创建对象
等你调用 getBean(...)
,或容器启动时自动加载,Spring 就会根据前面注册的 BeanDefinition
信息,正式实例化这个对象。
这时有多种方式可以被用来创建:
🧱 三、Spring 常见的实例化方式
✅ 1. 构造器实例化(最基本)
就像你自己写的 new UserService(...)
一样,Spring 也可以这样帮你造。
方式包括:
- XML:用
<constructor-arg>
- 注解:
@Bean
方法中直接new
- Java API:设置构造参数到
BeanDefinition
👉 适合对象比较简单的情况,Spring 默认也优先用构造方法。
✅ 2. 静态工厂方法实例化
不直接 new,而是调用一个类里的静态方法:UserFactory.createUser()
。
- XML:设置
factory-method
- 注解:
@Bean return XxxFactory.createXxx()
- Java API:设置
setFactoryMethod(...)
👉 好处是创建逻辑可以被抽离出来,不写死在类里。
✅ 3. 实例工厂方法实例化
先创建一个“工厂 Bean”,然后再调用它的实例方法造出你想要的对象。
- XML:
factory-bean + factory-method
- 注解:先
@Bean
工厂,再@Bean
调用工厂方法 - Java API:注册工厂类的 Bean,再配置工厂方法
👉 适合创建逻辑复杂、有依赖、有状态的 Bean。
✅ 4. FactoryBean 方式(Spring 高级工厂机制)
实现 Spring 提供的 FactoryBean<T>
接口,把你写的类当成一个“Bean 工厂”。
- Spring 会自动调用你的
getObject()
方法来创建目标对象
👉 特别适合框架作者或复杂场景,比如 MyBatis 的 SqlSessionFactoryBean
,代理工厂、动态代理、JPA 等都在用。
✅ 5. ServiceLoaderFactoryBean(基于 Java SPI)
使用 Java 原生的 ServiceLoader 机制自动加载某接口的多个实现。
- Spring 会读取
META-INF/services/
中的配置,自动创建所有实现类的集合
👉 适合插件架构、动态扩展组件。
✅ 6. createBean(…)(手动创建 Bean 实例)
调用 AutowireCapableBeanFactory#createBean(...)
,你可以在代码中直接手动创建一个 Bean,并让 Spring 自动帮你注入依赖。
👉 非常灵活!适合临时创建、运行时加载、测试、插件等场景。
✅ 7. registerBeanDefinition(…)(注册 Bean 的说明书)
这是整个流程的“起点”。你通过它告诉 Spring:
“我有一个 Bean,它长什么样,用哪个类,怎么造”
但这一步只是注册,并不会立刻创建对象。
🧠 四、整个流程串起来:
-
🌱 注册阶段
- 你定义了类和配置
- Spring 把它变成
BeanDefinition
- 通过
registerBeanDefinition()
注册到容器
-
🛠️ 实例化阶段
-
Spring 需要用到 Bean 时
-
它根据
BeanDefinition
中的规则,选择合适的实例化方式:- 构造器?
- 静态方法?
- 实例工厂?
- FactoryBean?
-
然后调用底层的
createBean(...)
-
-
🔄 依赖注入 + 初始化
- 自动注入
@Autowired
- 执行
@PostConstruct
/ 初始化方法等
- 自动注入
-
✅ 对象就绪!你可以使用它了!
📌 五、几点建议给初学者
- 不要一上来就死啃源码,先理解整体流程
- 常见业务开发时,构造器、
@Bean
和@Component
就够用了 - 需要动态、框架级操作时再去掌握 FactoryBean 和 createBean 等高级用法
- 看源码推荐从:
AbstractAutowireCapableBeanFactory#createBeanInstance
开始
2025年5月9日00:40:44
🌱 Spring Bean 注册与生命周期机制完整学习总结
1️⃣ Bean 的初始化与销毁机制
Spring 管理的 Bean 生命周期包含多个阶段:实例化 → 依赖注入 → 初始化 → 使用 → 销毁。Spring 提供了多种方式来自定义初始化与销毁逻辑。
✅ 1.1 注解方式:@PostConstruct
与 @PreDestroy
public class MyBean {
@PostConstruct
public void init() {
System.out.println("Bean 初始化");
}
@PreDestroy
public void destroy() {
System.out.println("Bean 销毁");
}
}
✅ 1.2 @Bean
指定方法
用于第三方类或更强控制:
@Configuration
public class AppConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public MyBean myBean() {
return new MyBean();
}
}
📌 初始化与销毁的调用顺序(Spring 默认):
初始化:
- 构造方法(实例化)
- 依赖注入
BeanPostProcessor.postProcessBeforeInitialization
@PostConstruct
或afterPropertiesSet()
或initMethod
BeanPostProcessor.postProcessAfterInitialization
销毁:
@PreDestroy
DisposableBean.destroy()
@Bean(destroyMethod=...)
2️⃣ Bean 的作用范围(Scope)
Scope 决定了一个 Bean 实例的创建频率和共享范围。
Scope | 生命周期说明 | 场景举例 |
---|---|---|
singleton | 默认,全局单例 | 所有服务类、工具类等 |
prototype | 每次注入时创建新对象 | 临时状态对象、不可共享类 |
request | 每个 HTTP 请求独立创建一个实例(Web 环境) | Web 表单处理器、登录请求对象 |
session | 每个用户会话维持一个实例(Web 环境) | 购物车、用户会话状态 |
application | 整个 Web 应用共享一个(ServletContext 级别) | Web 应用全局配置或资源管理 |
websocket | 每个 WebSocket 连接一个实例(Web 环境) | 聊天连接处理、实时推送通道 |
@Component
@Scope("request")
public class RequestBean {}
3️⃣ Bean 注册注解的区别:@Component
vs @Bean
✅ @Component
:
- 用于类上
- 配合
@ComponentScan
自动发现 - 适合自己写的类(可修改源码)
@Component
public class UserService {}
✅ @Bean
:
- 用于方法上
- 手动注册、可定义构造逻辑
- 适合注册第三方类、复杂构造
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
return mapper;
}
📌 总结对比:
特性 | @Component | @Bean |
---|---|---|
注解位置 | 类上 | 方法上 |
注册方式 | 扫描发现 | 显式配置 |
控制力 | 较低 | 高,自定义配置灵活 |
适合对象 | 自己写的类 | 第三方类、无法修改源码的类 |
4️⃣ 为什么要用 @Bean
注解注册第三方类?
因为:
- 第三方类不能加
@Component
- 你需要定制构造逻辑(如设置参数、初始化操作)
5️⃣ @Bean
方法的参数能自动注入吗?
✅ 可以!
Spring 会自动从 IOC 容器中查找匹配类型的 Bean 并注入进参数中。这叫方法参数注入机制。
🌟 示例:
@Bean
public MyCustomModule module() {
return new MyCustomModule();
}
@Bean
public ObjectMapper objectMapper(MyCustomModule module) {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module); // 自动注入
return mapper;
}
✔ 顺序无关,Spring 会先分析依赖,再按需调用。
📌 注入规则总结:
- 按类型自动注入
- 支持多个参数
- 支持泛型(如 List、Map)
- 支持
@Qualifier
精确指定 - 未注册则抛异常(除非加
@Nullable
/Optional
) - 方法顺序无关,Spring 会按依赖关系执行
6️⃣ @Mapper 注解和 @MapperScan 的使用
在使用 MyBatis 时:
@Mapper
:标注接口为 Mapper- 但必须搭配
@MapperScan("包路径")
,否则 Spring 不会自动识别这些接口
推荐配置:
@SpringBootApplication
@MapperScan("com.example.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
✔ 可以省去每个接口上的
@Mapper
注解
7️⃣ 常见问题与注意事项汇总
问题 | 原因与解决方案 |
---|---|
Bean 方法参数注入失败 | 检查依赖是否已注册为 Bean,或类型是否冲突 |
@Mapper 没生效 | 忘记加 @MapperScan ,或扫描路径写错 |
多个同类 Bean 不知道注入哪一个 | 使用 @Qualifier("beanName") 明确指定 |
Bean 初始化方法没调用 | 可能是没有 @PostConstruct / initMethod 配置 |
循环依赖异常 CurrentlyInCreation | 拆分逻辑,避免互相调用 |
✅ 总结一句话
Spring 提供了丰富而灵活的 Bean 注册与生命周期控制机制。理解
@Component
与@Bean
的差异、掌握依赖注入的执行时机、合理运用作用域与配置方式,是写出高质量 Spring 应用的基础。