尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
《SpringBoot 3:入门与应用实战》第 3 章 IOC 容器中的 Bean 阅读笔记 1
《SpringBoot 3入门与应用实战》第 3 章 IOC 容器中的 Bean 阅读笔记 1IOC 容器中存放和管理的大多数是与程序运行相关的 Bean在 Spring Framework 中对象被统称为 Bean组件​即能被 Spring Framework 的 IOC 容器创建或管理的对象都可以称为 Bean组件​。通过编写 XML 配置文件或注解配置类将第三方框架的核心 API 注册为 IOC 容器中的 Bean这些核心 API 对象会在适当的位置发挥其作用以支撑项目的正常运行。一个 Bean 的定义中可以包含以下因素Bean 的 Name​Bean 的所属类/接口信息Bean的作用域单实例或多实例。Bean 内部的依赖关系即 Bean 的内部注入了哪些属性和其他 Bean。Bean 的实例化方式即由构造方法创建还是由工厂方法创建。Bean 的生命周期是否包含对象创建后的初始化动作和对象被回收前的销毁动作。Bean 和对象有什么区别在学习 Spring 时经常遇见 Bean 的概念Bean 和 Java 中的对象有什么区别。Bean 其实就是 Java 中的对象在 Spring Framework 中为了跟 Java new 出的对象区分把注入到 IOC 容器中的 Java 对象称为 Bean。Spring Framework 的核心特性之一就是 IOC 控制反转把创建和管理对象交给 Spring Framework 的 IOC 的容器我们直接使用 IOC 容器不用自己去创建和管理对象。3.1 Bean的类型在 Spring Framework 中Bean 有两种类型普通 Bean 和工厂 Bean (FactoryBean)。3.1.1 普通 Bean普通 Bean 的定义非常好理解第 2 章中的所有 Bean 都是普通 Bean包括使用 Component 注解及其派生注解标注的 Bean以及使用 标签、Bean 注解定义的 Bean。3.1.2 FactoryBean除了普通的 BeanSpring Framework 还考虑到特殊情况某些 Bean 的创建过程比较复杂使用 XML 配置文件或者注解声明较难甚至无法完成。因而引入了 FactoryBean 机制借助工厂方法创建 Bean 对象。1.理解 FactoryBeanFactoryBean 是一个接口如果某个类实现了 FactoryBean 接口它将不再是一个普通 Bean而是一个创建对象的工厂。2.FactoryBean 的使用通过简单示例演示 FactoryBean 的使用。假设小朋友要买玩具由玩具工厂给小朋友制造玩具。(1)声明小朋友玩具首先声明小朋友类 ChildChild类中添加一个 wantToy 的属性指代小朋友想买的玩具类别。之后我们再创建一个玩具的抽象类 Toy 和两个具体的子类球类 Ball 和玩具汽车类 Car。packagecom.yangjunbo.bean.examplea;publicclassChild{// 当前小朋友想玩球privateStringwantToyball;publicStringgetWantToy(){returnwantToy;}}packagecom.yangjunbo.bean.examplea;publicabstractclassToy{privateStringname;publicToy(Stringname){this.namename;}}packagecom.yangjunbo.bean.examplea;publicclassBallextendsToy{// 球publicBall(Stringname){super(name);}}packagecom.yangjunbo.bean.examplea;publicclassCarextendsToy{// 玩具汽车publicCar(Stringname){super(name);}}(2)声明玩具工厂接下来声明一个玩具工厂类 ToyFactoryBean使其实现 FactoryBean 接口并指定泛型为 Toy。由需求分析可知玩具工厂只有知道小朋友想买什么玩具才能对应地生产从代码逻辑上讲玩具工厂应当依赖小朋友由小朋友为它提供玩具类别由此可知 ToyFactoryBean 中应当注入 Child 对象。ToyFactoryBean 实现 FactoryBean 接口时需要至少实现两个方法包含生产目标对象的类型以及生产的逻辑。packagecom.yangjunbo.bean.examplea;importorg.springframework.beans.factory.FactoryBean;publicclassToyFactoryBeanimplementsFactoryBeanToy{privateChildchild;OverridepublicToygetObject()throwsException{switch(child.getWantToy()){caseball:returnnewBall(ball);casecar:returnnewCar(car);default:// Spring Framework 2.0开始允许返回null之前的1.x版本不允许returnnull;}}OverridepublicClassToygetObjectType(){returnToy.class;}publicvoidsetChild(Childchild){this.childchild;}}(3)注册玩具工厂使用注解配置类 BeanTypeConfiguration 将上述的 Child 和 ToyFactoryBean 注入到 IOC 容器中。packagecom.yangjunbo.bean.examplea;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationpublicclassBeanTypeConfiguration{BeanpublicChildchild(){returnnewChild();}BeanpublicToyFactoryBeantoyFactory(){ToyFactoryBeantoyFactorynewToyFactoryBean();toyFactory.setChild(child());returntoyFactory;}}(4)测试效果编写测试启动类 BeanTypeAnnoApplication使用 BeanTypeConfiguration 配置类驱动 IOC 容器并直接从容器中获取 Toy 对象。由于ToyFactoryBean 实现了 FactoryBean 接口在获取 Toy 对象时会触发 getObject 方法进而生成一个 Toy 对象。运行 main 方法之后控制台可以正确打印出 “ball”​证明 ToyFactoryBean 已经创建出了 Ball 对象。packagecom.yangjunbo.bean.examplea;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassBeanTypeAnnoApplication{publicstaticvoidmain(String[]args)throwsException{ApplicationContextctxnewAnnotationConfigApplicationContext(BeanTypeConfiguration.class);Toytoyctx.getBean(Toy.class);System.out.println(toy);}}3.FactoryBean 与 Bean 同时存在如果 IOC 容器中同时存在 FactoryBean 与对应目标类型的 Bean则最终效果如何为了验证该效果我们在 BeanTypeConfiguration 中使用 Bean 注解手动注册一个 Ball 对象。接下来不修改 BeanTypeAnnoApplication 启动类直接运行 main 方法可以发现控制台抛出 NoUniqueBeanDefinitionException 异常提示 IOC 容器中有两个 Toy 对象。由此得出一个结论FactoryBean 创建的 bean 对象会直接放在 IOC 容器中。如果修改一下 BeanTypeAnnoApplication 中 main 方法的代码将获取单个 Toy 对象改为获取全部 Toy 对象。重新运行 main 方法可以发现控制台打印了两个 toy通过 ToyFactoryBean 创建出来的 Ball 对象的名称叫 toyFactory。packagecom.yangjunbo.bean.examplea;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;ConfigurationpublicclassBeanTypeConfiguration{BeanpublicChildchild(){returnnewChild();}BeanpublicToyFactoryBeantoyFactory(){ToyFactoryBeantoyFactorynewToyFactoryBean();toyFactory.setChild(child());returntoyFactory;}BeanpublicBallball(){returnnewBall(ball);}}packagecom.yangjunbo.bean.examplea;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;importjava.util.Map;publicclassBeanTypeAnnoApplication{publicstaticvoidmain(String[]args)throwsException{ApplicationContextctxnewAnnotationConfigApplicationContext(BeanTypeConfiguration.class);//Toy toy ctx.getBean(Toy.class);//System.out.println(toy);MapString,Toytoysctx.getBeansOfType(Toy.class);toys.forEach((name,toy)-{System.out.println(toy name : name, toy.toString());});}}4.取出 FactoryBean 本体取出 FactoryBean 本体有两种方式第一种是使用 FactoryBean 的类型获取即 ctx.getBean(ToyFactoryBean.class)第二种是在 Bean 的 id 前面加一个 符号即 ctx.getBean(“toyFactory”)。packagecom.yangjunbo.bean.examplea;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;importjava.util.Map;publicclassBeanTypeAnnoApplication{publicstaticvoidmain(String[]args)throwsException{ApplicationContextctxnewAnnotationConfigApplicationContext(BeanTypeConfiguration.class);//Toy toy ctx.getBean(Toy.class);//System.out.println(toy);MapString,Toytoysctx.getBeansOfType(Toy.class);toys.forEach((name,toy)-{System.out.println(toy name : name, toy.toString());});System.out.println(ctx.getBean(ToyFactoryBean.class));System.out.println(ctx.getBean(toyFactory));}}5.FactoryBean 创建 Bean 的实例数FactoryBean 接口中有一个默认方法 isSingleton返回值默认为 true代表默认是单实例的。连续两次获取 Toy 对象并对比内存地址可以发现是同一个对象。如果在 ToyFactoryBean 中重写 isSingleton 方法并返回 false再连续两次获取 Toy 对象内存地址则不相同。packagecom.yangjunbo.bean.examplea;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;importjava.util.Map;publicclassBeanTypeAnnoApplication{publicstaticvoidmain(String[]args)throwsException{ApplicationContextctxnewAnnotationConfigApplicationContext(BeanTypeConfiguration.class);//Toy toy ctx.getBean(Toy.class);//System.out.println(toy);MapString,Toytoysctx.getBeansOfType(Toy.class);toys.forEach((name,toy)-{System.out.println(toy name : name, toy.toString());});System.out.println(ctx.getBean(ToyFactoryBean.class));System.out.println(ctx.getBean(toyFactory));System.out.println(ctx.getBean(toyFactory));System.out.println(ctx.getBean(toyFactory));}}packagecom.yangjunbo.bean.examplea;importorg.springframework.beans.factory.FactoryBean;publicclassToyFactoryBeanimplementsFactoryBeanToy{privateChildchild;OverridepublicToygetObject()throwsException{switch(child.getWantToy()){caseball:returnnewBall(ball);casecar:returnnewCar(car);default:// Spring Framework 2.0开始允许返回null之前的1.x版本不允许returnnull;}}OverridepublicClassToygetObjectType(){returnToy.class;}publicvoidsetChild(Childchild){this.childchild;}OverridepublicbooleanisSingleton(){returnfalse;}}6.FactoryBean 创建 Bean 的时机IOC 容器中的普通 Bean 都是随 IOC 容器的初始化而一并创建的那么 FactoryBean 与创建的目标对象是否同时创建我们可以在 Toy 和ToyFactoryBean 的内部声明无参构造方法并添加控制台打印。创建一个新的启动类 BeanTypeAnnoApplicationmain 方法中只有创建 ApplicationContext 一行代码运行main方法可以发现控制台只打印了 ToyFactoryBean 的初始化文字而 Toy 的初始化文字并没有被打印由此得出结论FactoryBean 本身的加载是随 IOC 容器的初始化时机一并创建的。控制台并没有打印 “生产了一个” name说明 FactoryBean 中要创建的 Bean 还没有被加载**由此也就得出另一个结论FactoryBean 生产Bean 的机制是延迟生产。**如果在初始化 ApplicationContext 后再获取 Toy 对象此时会打印“生产了一个 ball”​印证了刚才的结论。packagecom.yangjunbo.bean.exampleb;importorg.springframework.context.ApplicationContext;importorg.springframework.context.annotation.AnnotationConfigApplicationContext;publicclassBeanTypeAnnoApplication{publicstaticvoidmain(String[]args)throwsException{ApplicationContextctxnewAnnotationConfigApplicationContext(BeanTypeConfiguration.class);ctx.getBean(Toy.class);}}7.BeanFactory 与 FactoryBean 的区别BeanFactorySpring Framework 中实现 IOC 的底层容器​。FactoryBean用于创建 Bean 的工厂 Bean适合用来创建一些初始化流程比较复杂的 Bean。
RELATED

相关推荐

构建纯本地私人知识库:RAG架构、本地大模型与Tauri桌面应用实战

构建纯本地私人知识库:RAG架构、本地大模型与Tauri桌面应用实战

1. 项目概述:为什么我们需要一个纯本地的私人知识库?最近几年,AI大模型的能力突飞猛进,尤其是检索增强生成(RAG)技术,让大模型能够“阅读”我们自己的文档并给出精准回答,这简直是知…

📅 2026/9/10 10:40:49
碳化硅外延厚度预测:从数据清洗到模型构建的完整建模指南

碳化硅外延厚度预测:从数据清洗到模型构建的完整建模指南

1. 从“测不准”到“算得准”:碳化硅外延厚度建模的挑战与机遇在半导体制造,尤其是以碳化硅(SiC)为代表的第三代半导体领域,外延层厚度是一个关乎器件性能与良率的命脉参数。它直接决定了器件的耐压等级、导通电阻和开…

📅 2026/10/24 19:14:12
电容选型实战指南:从核心参数到典型应用避坑

电容选型实战指南:从核心参数到典型应用避坑

1. 从一次电源啸叫说起:为什么电容选型不是小事?前段时间,我调试一块新设计的电机驱动板,上电后电机还没转,电源部分就传来一阵尖锐的“滋滋”声。用示波器一量,12V输入端的纹波大得吓人,峰峰值…

📅 2026/10/14 0:46:59
MORE NEWS

更多资讯

📰

Linux系统清理工具‘降尘丹‘详解与实战

1. Linux系统清理工具"降尘丹"解析作为一名Linux系统管理员,我经常遇到服务器运行一段时间后性能下降的问题。经过多年实践,我整理出一套名为"降尘丹"的系统清理方案,专门解决Linux系统长期运行产生的各种"垃圾&quo…

📰

YOLOv10模块化改进与目标检测优化实践

1. YOLOv10模块化改进方案概述 YOLOv10作为目标检测领域的最新力作,在保持YOLO系列实时性优势的同时,通过模块化设计大幅提升了模型的可扩展性。这次改进的核心在于构建了一套完整的即插即用模块库,包含CIB(Cross-stage Inverted …

📰

Phong光照模型原理与实时渲染优化实践

## 1. Phong光照模型基础解析1975年由Bui Tuong Phong提出的Phong模型,至今仍是计算机图形学中最经典的光照计算方法。这个模型之所以能经久不衰,核心在于它用相对简单的数学公式,实现了对物体表面光照现象的合理近似。### 1.1 模型组成要素P…

📰

讯飞火星WebAPI工业级接入指南:鉴权、流式与稳定性实战

1. 项目概述:这不是调用一个API,而是接入一套工业级AI能力中枢 “调用讯飞火星AI大模型WebAPI”——这八个字背后,不是一行curl命令就能打发的轻量集成,而是一次面向生产环境的AI能力接入工程。我过去三年在某高校智能教育实验室、…

📰

讯飞火星大模型WebAPI调用实战指南:鉴权、流式响应与避坑要点

1. 项目概述:为什么“调用讯飞火星AI大模型WebAPI”正在成为一线开发者的高频刚需最近两周,我在某高校智能交互实验室带一个本科生创新项目,主题是“面向老年用户的语音助记App”。团队里三个同学刚接触大模型接口开发,头两天卡在…

📰

中文影评情感分析系统:BiLSTM-CRF工程实践指南

1. 项目概述:这不是一个“跑通模型”的作业,而是一次真实场景下的端到端工程实践“毕业设计:基于深度学习的电影评论情感分析系统”——这个标题在每年春季的高校毕设选题表里高频出现,但真正能跑出可用结果、经得起用户随手输入一…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬