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 ConcurrentHashMapClass?, Object beanCache new ConcurrentHashMap(); // 获取或创建 Bean支持单例模式 SuppressWarnings(unchecked) public static T T getBean(ClassT clazz) { // 先从缓存中获取 Object bean beanCache.get(clazz); if (bean null) { // 双重检查锁简化版实际可加锁 synchronized (SimpleContainer.class) { bean beanCache.get(clazz); if (bean null) { try { // 假设类有无参构造函数 ConstructorT 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(ClassT)方法若对象不存在则通过反射创建并递归注入其依赖字段级。依赖注入逻辑非常简化实际 Spring 等框架会通过注解如Autowired、类型匹配、作用域等更复杂的机制处理。此伪代码假设所有类都有无参构造函数且所有非基本类型字段都需要注入。当然对于对象管理这一块业务功能可以自己手动实现的简易容器、也可以自己手动引入这个方面的依赖包Google Guice、Java EE CDI、PicoContainer不过 Java里面最强大还得是Spring Bean1.2 Spring Bean 与 其他对象管理工具 区别Spring Bean 与其他对象管理工具如手动实现的简易容器、Google Guice、Java EE CDI、PicoContainer 等在设计目标、功能完整性、生态集成等方面存在显著区别。1. ** vs 手动编写的简易容器如上文伪代码**功能完整性仅支持基本单例缓存和简单反射创建完整的 IoC/DI、生命周期、作用域、AOP 等线程安全需自行处理如加锁容器本身线程安全Bean 作用域可控依赖解析通常只支持字段注入无类型/泛型处理支持复杂依赖图解析、循环依赖处理部分场景可维护性代码耦合高难以扩展配置与逻辑分离易于测试和维护适用场景教学演示、极简项目企业级应用开发✅结论简易容器适合理解 IoC 原理但无法替代 Spring。2. ** vs Google Guice**配置方式纯 JavaModule Inject注解/XML/Java Config 多种方式学习曲线轻量、API 简洁功能丰富但较复杂AOP 支持依赖 AOP Alliance功能较弱内置强大 AOP基于代理生态整合无官方 Web/DB/Security 支持完整 Spring 生态Boot, Data, Security 等适用场景轻量级应用、Android、非 Spring 项目企业级 Java 应用主流选择✅结论Guice 更轻量Spring 更全能。3. ** vs Java EE CDIContexts 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 配置适合嵌入式或测试场景。DaggerGoogle编译时依赖注入主要用于 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 BeanSpring 容器管理的“对象实例” 定义ASpring Beanis any object that isinstantiated, assembled, and managed by the Spring IoC container.一个 Spring Bean 是任何由 Spring IOC 容器实例化组装和管理的对象2.3 ✅ Spring Bean 不要求满足 JavaBean 规范可以没有无参构造用构造器注入可以没有 setter用字段注入或构造注入可以是抽象类的子类、内部类、甚至 Lambda某些场景 设计目标依赖注入DI生命周期管理PostConstruct,DisposableBeanAOP 代理作用域控制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 Beanpublic 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 Bean2.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、ApplicationContext3.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暂时先忽略 BeanDefinitionRegistryRootBeanDefinition... 等这类具体的作用的什么。先熟悉一个Bean 的基本创建流程。