Spring 的 Bean 对象什么?
一,Spring 的 Bean 对象什么?
1.1 Bean对象是什么?
在Java传统的项目里面,代码各层之间的对象引入与调用基本上都是通过关键字 new 创建出来。对象之间的依赖关系是由程序员手动管理。这种方式代码耦合度极高,维护成本极高。
并且每次请求都是会重新创建一次,从Controller 层,Service层,Mapper层 三层之间的对象依赖引入都会重新创建一次。最开始是程序员之间自己会写一个简单的工具类容器由于管理对象,在请求到的时候,比如请求到Controller层,而Controller 引用了 10 个service 的对象,先去容器里面查询是否拥有对应的引用对象,有就直接使用,没有则创建新的,这样大大减少内存的消耗,以及频繁创建对象性能消耗。
1.2 简单案例
import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.Constructor;
// 简易对象容器(单例)
public class SimpleContainer {
// 使用 ConcurrentHashMap 确保线程安全
private static final ConcurrentHashMap<Class<?>, Object> beanCache = new ConcurrentHashMap<>();
// 获取或创建 Bean(支持单例模式)
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<T> clazz) {
// 先从缓存中获取
Object bean = beanCache.get(clazz);
if (bean == null) {
// 双重检查锁(简化版,实际可加锁)
synchronized (SimpleContainer.class) {
bean = beanCache.get(clazz);
if (bean == null) {
try {
// 假设类有无参构造函数
Constructor<T> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
bean = constructor.newInstance();
// 自动注入依赖(简化:只处理字段上的 @Autowired 模拟)
injectDependencies(bean);
// 放入缓存(单例)
beanCache.put(clazz, bean);
} catch (Exception e) {
throw new RuntimeException("Failed to create bean: " + clazz.getName(), e);
}
}
}
}
return (T) bean;
}
// 简单依赖注入(模拟 @Autowired)
private static void injectDependencies(Object bean) throws Exception {
Class<?> clazz = bean.getClass();
for (var field : clazz.getDeclaredFields()) {
// 假设所有字段都需要注入(实际应检查注解如 @Autowired)
if (!field.getType().isPrimitive()) {
field.setAccessible(true);
Object dependency = getBean(field.getType());
field.set(bean, dependency);
}
}
}
}
// 示例:Controller 层
class UserController {
// 依赖注入
private UserService userService;
private OrderService orderService;
// ... 其他 8 个 service
public void handleRequest() {
userService.process();
orderService.process();
}
}
// 示例:Service 层
class UserService {
private UserMapper userMapper;
public void process() {
userMapper.query();
}
}
class OrderService {
public void process() {
System.out.println("Processing order...");
}
}
// 示例:Mapper 层
class UserMapper {
public void query() {
System.out.println("Querying user from DB...");
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
// 模拟请求入口:获取 Controller(自动注入所有依赖)
UserController controller = SimpleContainer.getBean(UserController.class);
// 处理请求(所有依赖对象只创建一次)
controller.handleRequest();
}
}
SimpleContainer是一个静态工具类容器,内部使用ConcurrentHashMap缓存已创建的对象(模拟单例)。getBean(Class<T>)方法:若对象不存在则通过反射创建,并递归注入其依赖(字段级)。- 依赖注入逻辑非常简化,实际 Spring 等框架会通过注解(如
@Autowired)、类型匹配、作用域等更复杂的机制处理。 - 此伪代码假设所有类都有无参构造函数,且所有非基本类型字段都需要注入。
当然,对于对象管理这一块业务功能,可以自己手动实现的简易容器、也可以自己手动引入这个方面的依赖包:Google Guice、Java EE CDI、PicoContainer
不过 Java里面最强大,还得是Spring Bean
1.2 Spring Bean 与 其他对象管理工具 区别
Spring Bean 与其他对象管理工具(如手动实现的简易容器、Google Guice、Java EE CDI、PicoContainer 等)在设计目标、功能完整性、生态集成等方面存在显著区别。
1. ** vs 手动编写的简易容器(如上文伪代码)**
|
功能完整性 |
仅支持基本单例缓存和简单反射创建 |
完整的 IoC/DI、生命周期、作用域、AOP 等 |
|
线程安全 |
需自行处理(如加锁) |
容器本身线程安全,Bean 作用域可控 |
|
依赖解析 |
通常只支持字段注入,无类型/泛型处理 |
支持复杂依赖图解析、循环依赖处理(部分场景) |
|
可维护性 |
代码耦合高,难以扩展 |
配置与逻辑分离,易于测试和维护 |
|
适用场景 |
教学演示、极简项目 |
企业级应用开发 |
✅ 结论:简易容器适合理解 IoC 原理,但无法替代 Spring。
2. ** vs Google Guice**
|
配置方式 |
纯 Java(Module + |
注解/XML/Java Config 多种方式 |
|
学习曲线 |
轻量、API 简洁 |
功能丰富但较复杂 |
|
AOP 支持 |
依赖 AOP Alliance,功能较弱 |
内置强大 AOP(基于代理) |
|
生态整合 |
无官方 Web/DB/Security 支持 |
完整 Spring 生态(Boot, Data, Security 等) |
|
适用场景 |
轻量级应用、Android、非 Spring 项目 |
企业级 Java 应用主流选择 |
✅ 结论:Guice 更轻量,Spring 更全能。
3. ** vs Java EE CDI(Contexts and Dependency Injection)**
|
标准 |
Java EE/Jakarta EE 官方标准 |
Spring 自有实现(事实标准) |
|
作用域 |
内置 Request/Session/Application 等 Web 作用域 |
需 Web 环境支持(如 Spring MVC) |
|
事件模型 |
强大的事件与观察者机制 |
基础事件支持 |
|
可移植性 |
可在任何 Jakarta EE 容器运行 |
依赖 Spring 容器 |
|
流行度 |
在 Jakarta EE 生态中使用 |
在 Spring 生态中占绝对主导 |
✅ 结论:CDI 是 Jakarta EE 的标准方案,Spring 是事实上的行业标准。
4. ** vs PicoContainer / Dagger 等**
- PicoContainer:极简 IoC,无注解,纯 API 配置,适合嵌入式或测试场景。
- Dagger(Google):编译时依赖注入(主要用于 Android),无运行时反射,性能高但灵活性低。
- Spring:运行时注入,功能全面,适合复杂业务系统。
关键区别总结
|
定位 |
企业级全栈框架的核心组件 |
轻量级、专用或标准实现 |
|
功能广度 |
极广(IoC + AOP + 事务 + 安全 + Web + ...) |
通常只专注依赖注入 |
|
配置灵活性 |
极高(多种配置方式 + 条件化) |
通常较固定(如 Guice 只用 Java) |
|
社区与生态 |
庞大(Spring Boot 自动配置降低门槛) |
相对小众或局限于特定平台 |
|
性能 |
运行时反射(可通过优化缓解) |
部分工具(如 Dagger)编译时生成,性能更高 |
二,JavaBeans 组件规范
在讲解 Spring Bean 之前,首先需要了解的到的是 JavaBeans 相关的概念。
JavaBeans 是什么?和 Spring中概念的"Bean" 有什么区别?
首先,JavaBeans 是 Sun Microsystems 在 1997 年提出的一套组件规范,目标是
- 创建可复用、可配置、可可视化(如 IDE 拖拽)的 Java 组件。
- 支持内省(Introspection):在运行时自动发现对象的属性、方法、事件等。
📌 关键点:JavaBeans 是一套约定 + API,不是 Spring 发明的!
2.1 ✅ JavaBean 必须满足的约定:
-
- 公共无参构造函数(
public MyBean()) - 属性通过 getter/setter 访问(如
getName()/setName(String)) - 实现
Serializable接口(可选,但推荐) - 是具体的类(非抽象)
- 公共无参构造函数(
其中编写java的时候,体现最多的就是java的普通实体类 Entry上,其中的属性都是通过getting,setting进行获取与设置。但是常规的Service 层,Mapper 层都不符合JavaBeans 的规范。但是Spring 只要是对象就可以被管理。
2.2 ✅Spring Bean:Spring 容器管理的“对象实例”
📌 定义
A Spring Bean is any object that is instantiated, assembled, and managed by the Spring IoC container.
一个 Spring Bean 是任何由 Spring IOC 容器实例化,组装和管理的对象
2.3 ✅ Spring Bean 不要求满足 JavaBean 规范:
- 可以没有无参构造(用构造器注入)
- 可以没有 setter(用字段注入或构造注入)
- 可以是抽象类的子类、内部类、甚至 Lambda(某些场景)
🎯 设计目标:
依赖注入(DI)
生命周期管理(@PostConstruct, DisposableBean)
AOP 代理
作用域控制(singleton, prototype 等)
🔧 核心机制:
BeanFactory/ApplicationContextBeanDefinitionBeanPostProcessor
图1:用图展示关系:
Java Object
│
├── (符合规范) → JavaBean → 可被 Introspector 分析
│
└── (被 Spring 管理) → Spring Bean(无论是否是 JavaBean)
图 2:继承与实现关系(简化版)
+---------------------+
| java.lang.Object |
+---------------------+
▲
|
+---------------------+ +----------------------+
| JavaBean | | Spring Bean |
| (conforms to spec) | | (managed by Spring) |
+---------------------+ +----------------------+
| - public no-arg | | - Any Java object |
| constructor | | - No spec required |
| - getXxx()/setXxx() | | - Managed by |
| - Serializable | | ApplicationContext |
+---------------------+ +----------------------+
▲ ▲
| |
+---------------------+ +----------------------+
| MyUserBean | | OrderService |
| (valid JavaBean) | | (NOT a JavaBean, |
+---------------------+ | but a Spring Bean) |
+----------------------+
| - private final Repo |
| - public OrderService(Repo) |
+----------------------+
💡 说明:
MyUserBean同时是 JavaBean 和 Spring BeanOrderService是 Spring Bean,但不是 JavaBean(无无参构造、无 setter)
图 3:容器与内省机制对比
+------------------+ +-----------------------+
| Builder Tool | | Spring Container |
| (e.g. NetBeans) | | (ApplicationContext) |
+------------------+ +-----------------------+
| |
| uses Introspector | uses BeanFactory
▼ ▼
+------------------+ +-----------------------+
| JavaBean | | Any Java Object |
| (must follow | | (no constraints) |
| JavaBeans spec)| | |
+------------------+ +-----------------------+
▲ ▲
| |
+------------------+ +-----------------------+
| PropertyEditor | | BeanPostProcessor |
| (type conversion)| | (AOP, init, etc.) |
+------------------+ +-----------------------+
代码示例:直观对比
✅ 合法的 JavaBean(也是 Spring Bean)
public class Person implements Serializable {
private String name;
public Person() {} // 无参构造
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
@Service
public class PaymentService {
private final UserRepository userRepo; // final 字段
// 无无参构造,无 setter
public PaymentService(UserRepository userRepo) {
this.userRepo = userRepo;
}
public void process() { /* ... */ }
}
🔥 这个 PaymentService不符合 JavaBean 规范(无无参构造、无 setter),但它是完全合法的 Spring Bean!
2.4 JavaBeans 核心设计组件解析
JavaBeans 是所属在 java.beans 包下的;源码如下:
package java.beans;
import java.awt.Image;
/**
* @since 1.1
*/
public interface BeanInfo {
/**
* BeanDescriptor —— Bean 自身的描述
* 描述 Bean 的基本信息:
* name:类名
* displayName:显示名称(用于 IDE)
* shortDescription:简短说明
* icon:可视化图标(Image)
*/
BeanDescriptor getBeanDescriptor();
/**
* EventSetDescriptor —— 事件集描述器
* 描述 Bean 能触发或监听的事件(基于 Observer 模式)
* 例如:addXXXListener / removeXXXListener 方法对。
*/
EventSetDescriptor[] getEventSetDescriptors();
/**
* 返回该 Bean 的默认事件在 EventSetDescriptor[] 数组中的索引。
*/
int getDefaultEventIndex();
/**
* PropertyDescriptor —— 属性描述器
* 描述一个属性(Property),对应 Java 中的 getter/setter 对。
*/
PropertyDescriptor[] getPropertyDescriptors();
/**
* 返回该 Bean 的默认属性在 PropertyDescriptor[] 数组中的索引。
*/
int getDefaultPropertyIndex();
/**
* MethodDescriptor —— 方法描述器
* 描述 Bean 中的公开方法(除属性 getter/setter 外)。
* 包含方法名、参数、返回类型、异常等。
* 📌 注意:
* 属性的 getter/setter 通常不包含在 MethodDescriptor 中,
* 它们属于 PropertyDescriptor。
*/
MethodDescriptor[] getMethodDescriptors();
/**
* 许当前 BeanInfo 组合其他 BeanInfo 对象,实现元数据的继承或组合。
*/
BeanInfo[] getAdditionalBeanInfo();
/**
* Image —— 可视化图标
* BeanInfo 可提供 16x16 或 32x32 的图标,用于 IDE 工具箱。
* 通过 BeanDescriptor.getIcon(int iconKind) 获取。
* 🖼️ 这是 JavaBeans 可视化设计理念的体现,如今已基本淘汰。
*/
Image getIcon(int iconKind);
/**
* Constant to indicate a 16 x 16 color icon.
*/
static final int ICON_COLOR_16x16 = 1;
/**
* Constant to indicate a 32 x 32 color icon.
*/
static final int ICON_COLOR_32x32 = 2;
/**
* Constant to indicate a 16 x 16 monochrome icon.
*/
static final int ICON_MONO_16x16 = 3;
/**
* Constant to indicate a 32 x 32 monochrome icon.
*/
static final int ICON_MONO_32x32 = 4;
}
三,Spring Bean 设计讲解
在上面介绍了 JavaBeans 基本概念,从中我们得知 JavaBeans 是一套约定,且与Spring 没有任何关系。JavaBeans 的约定是
- 创建可复用、可配置、可可视化(如 IDE 拖拽)的 Java 组件。
- 支持内省(Introspection):在运行时自动发现对象的属性、方法、事件等。
Spring组件中提供的对象管理业务,其中里面管理的对象都统一称为“Bean”。项目里面的Service 层代码,Mapper层,配置层代码,过滤器,监听器等等,只要将对象交由Spring 统一管理对象以便复用。都称为“Bean”
换句话说:“Bean”这个是Spring 对象管理业务的管理对象的专业术语。
当然,在座的各位看官自己也可以写一个对象管理组件,其中管理的对象统一名称自己也可以随便取。比如叫ManagedObject(被管理的对象)
而这个被管理的对象可以是符合 JavaBeans 规范的对象,也可以是其他任意对象,甚至是Lambda 表达式写的写对象也都可以被spring 所管理。
3.1 为什么 Spring 创建一个Bean 流程比我们想象中的要复杂
在我们 1.2 简单案例 SimpleContainer 里面,仅仅只是通过反射 + 容器(ConcurrentHashMap) 进行一个对象存储以便复用。这个简单的容器的功能作用仅仅只是对象管理以便复用。
Spring 的 Bean 不仅仅只提供对象管理以便复用。还提供完整的 IoC/DI、生命周期、作用域、AOP 等。在设计Bean对象的时候,想要同时拥有这些对象,必然需要对Bean 的创建流程进行更复杂更细节更合理的拆分与设计。
3.2 Spring Bean 基本使用
由于Spring组件是一个企业级项目的全栈的核心组件,其中不仅仅只包含对象管理这一个业务。还是容器(IOC),AOP,事物等等。现在通过代码提供一个极简、干净、无业务语义的示例,专门用于说明“如何通过编码方式让 Spring 创建并管理一个 Bean”。
不使用 @Component、@Configuration、XML 等声明式方式
仅通过 Java 编码动态注册一个 Bean
展示 Spring 容器如何实例化、管理它
体现核心接口:BeanDefinitionRegistry、BeanFactory、ApplicationContext
3.3 示例代码(无业务,纯机制)
package com.toast.learn.spring.bean;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author toast
* @time 2025/10/15
* @remark
*/
class DemoBean {}
public class ProgrammaticBeanRegistration {
public static void main(String[] args) {
// 1. 创建一个未刷新的 ApplicationContext(底层是 DefaultListableBeanFactory)
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 2. 获取 BeanDefinition 注册表(本质是 DefaultListableBeanFactory)
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getBeanFactory();
// 3. 手动构造一个 BeanDefinition,描述 "要创建 DemoBean 的实例"
RootBeanDefinition beanDefinition = new RootBeanDefinition(DemoBean.class);
// 4. 将该定义注册到容器中,名字为 "demoBean"
registry.registerBeanDefinition("demoBean", beanDefinition);
// 5. 刷新容器:触发 BeanFactory 初始化、预处理、准备就绪
context.refresh();
// 6. 从容器中获取 Bean —— 此时 Spring 才真正创建 DemoBean 实例
DemoBean bean = context.getBean("demoBean", DemoBean.class);
// 7. 验证:该 Bean 确实由 Spring 创建并管理
System.out.println("Bean created by Spring: " + (bean != null)); // true
System.out.println("Bean class: " + bean.getClass().getName()); // DemoBean
context.close();
}
}
输出结果:
> Task :spring-learn:run
Bean created by Spring: true
Bean class: com.toast.learn.spring.bean.DemoBean
暂时先忽略 BeanDefinitionRegistry,RootBeanDefinition... 等这类具体的作用的什么。先熟悉一个Bean 的基本创建流程。
更多推荐




所有评论(0)