【Spring】-Spring中Bean对象的存取
作者
:学Java的冬瓜
博客主页
:☀冬瓜的主页🌙
专栏
:【Framework】
主要内容
:往spring中存储Bean对象的三大方式:XML方式(Bean标签);五大类注解;方法注解。从spring中取对象的两种方式:基本方法、注解方法(属性注入、set注入、构造方法注入)。
文章目录
- Spring中Bean的存取方式
- 一、三大方式存储对象到spring容器中
- 1、XML方式把Bean存储到spring
- 1.1、创建Bean类
- 1.2、将Bean注册到Spring的xml配置文件
- 2、五大类注解方式 @Controller等存储Bean到spring
- 2.1、五大类注解和JavaEE标准分层
- 2.2、五大类注解方式 往spring中 存储Bean对象
- 3、方法注解方式 @Bean存储对象到spring中
- 3.1、实体类的命名
- 3.2、存储Bean对象
- 二、获取Bean对象(依赖注入)
- 1、获取对象的最基本的方法
- 2.1、获取Spring容器方式
- 法一:BeanFactory接口和ClassPathResource继承类
- 法二:ApplicationContext接口和ClassPathXmlApplicationContext继承类
- 2.2、getBean获取指定的Bean对象
- 2.3、获取Bean对象的名称的命名源码分析
- 2、使用依赖注入从spring获取对象
- 2.1、法一:属性注入
- 2.2、法二:setter注入
- 2.3、法三:构造方法注入
- 补充:在依赖注入中 @Autowired和 @Resource的区别
Spring中Bean的存取方式
在Spring中,Bean的装配方式有两种,xml方式和注解方式。自己开发的类可以使用@Component注解或xml方式装配,推荐使用注解,因为更加简洁方便。
引入第三方库的包可以使用@Bean注解的方式或xml的方式,推荐使用xml方式,将库的内容和自己的代码分离。
一、三大方式存储对象到spring容器中
1、XML方式把Bean存储到spring
1.1、创建Bean类
a. 在Java目录下创建多级目录包com.spring.bean,在该包下创建Student类和Teacher类
b. Bean对象中,Student类如下(Teacher类的属性和方法与之相似,有私有属性,有Set和Get方法,构造方法)
package com.spring.bean;public class Student {private String name;private int age;public Student(){System.out.println("init Student");}public void wmi(){System.out.println("I am student: my name is "+ name);}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
1.2、将Bean注册到Spring的xml配置文件
a. 在
resources下创建spring中对象注册的配置文件
,可以命名为spring-config.xml
b.将下列配置信息粘贴到配置文件中,并且使用bean标签对student和teacher类进行注册,注册时id属性是对保存到spring中的
对象的重命名
,class 属性是该类在项目中的路径+包名+类名
,而相应的文件会从spring依赖中自动获取。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--将类对象,com.spring.bean.Student存进spring容器,名字是student,是一个spring bean--><bean id="student" class="com.spring.bean.Student"/><bean id="teacher" class="com.spring.bean.Teacher"/>
</beans>
2、五大类注解方式 @Controller等存储Bean到spring
2.1、五大类注解和JavaEE标准分层
A:五大类注解
@Controller:控制器,验证用户请求的数据的正确性 。
@Service:服务,调度具体的执行方法。
@Repository:用户持久层,和数据库进行交互。
@Component:组件(工具类)
@Configuration:配置项,项目中的一些配置。为什么有配置项类?有很多原因,有一个就是在启动程序时,配置文件不一定会加载,这时就需要使用配置项来起到在程序运行时告诉程序需要先加载配置文件的作用。
B:JavaEE标准分层
在后端的分层当中,至少有控制层、服务层,数据持久层三个层次。
C:使用五大类注解和标准分层规范项目
下图中:实体类使用entity或model表示,其他部分按照五大类注解的方式分层,分出控制器类,服务类,数据库操作类,组件,配置文件类。
2.2、五大类注解方式 往spring中 存储Bean对象
A:创建包,Bean对象,并给类(Bean对象)添加适当的五大类注解
注意:满足需要存储在spring中的类在配置文件的base-package中,且这个类使用了五大类注解,就可以使用spring进行存取。
B:创建spring配置文件spring-config.xml,并在配置文件中注册可能要存入spring所有类的所在包
在下图中,可能存入spring的类是TestController包下的任意一个类(或TestController包的字包中的类)。如下图,springTest包的子包中的类都将保存在spring中,所以注册包springTest:
base-package="springTest"
注意点:
- 在配置文件中注册可能涉及的包和存储的类使用五大类注解二者缺一不可,如果缺少,报错说没有找到这个Bean对象。
- 需要存储在spring中的类本身的位置可以在注册的包中或者它的子包中。
- 使用五大类注解和注册包这个方法与使用bean标签(XML方式)(使用
路径+包名+类名
)的方式可以混合使用。即如果存在某个类需要存储在spring中,但又不适合放在注册的包里的任何位置,就可以将这个类放在注册包之外,但是使用bean注册当前类对象(即使用XML的方式存取对象)。
3、方法注解方式 @Bean存储对象到spring中
3.1、实体类的命名
补充:
实体类的管理:实体类不交给spring管理,由我们自己管理
。
实体类的命名:
DO,基本对象,和数据库表结构一一对应,如UserEntity或UserDO或者直接和数据库表名一致 User
。
VO,扩展对象,前端传给后端的对象。如UserVO
,使用多个VO描述各种业务。
3.2、存储Bean对象
要点:
- 1> 方法注解需要配合五大类注解使用。比如UserBeans类下有多个方法注解,在UserBeans上需要加上五大类注解(一般是@Component)。之所以如此,是为了提高效率。
- 2> 方法注解的对象名可以改名。方法注解 对象的名字不同于五大类注解,方法注解是默认方法名,但是可以在方法注解@Bean后加括号,使用name或value属性给Bean对象改名。
注意:
- 给Bean对象改名后,就不能再使用方法名获取到对象,只能使用修改后的名字。
- 如果存在方法名相同的两个@Bean方法在不同类中(都未修改名字),当获取Bean对象时可以在方法上添加@Order(数字),数字小的方法会先注入,但是后注入的方法会发生覆盖。
二、获取Bean对象(依赖注入)
1、获取对象的最基本的方法
2.1、获取Spring容器方式
a.目的相同:
BeanFactory
和ApplicationContext
的目的相同,都是为了获取到spring容器
b.实现不同:
BeanFactory是使用类似于懒汉模式进行类加载并进行对象的初始化(获取到spring后,使用getBean方法获取对象时,才进行相关对象的类加载,并进行对象的初始化)。
ApplicationContext则是使用类似于饿汉模式(一获取spring容器会立即加载配置文件,并进行对象的初始化(执行构造方法,静态方法,静态代码块等))
c.父子关系:BeanFactory是ApplicationContext的子类
法一:BeanFactory接口和ClassPathResource继承类
给ClassPathResource传参spring的配置文件的文件名,给XmlBeanFactory传参ClassPathResource文件,最后BeanFactory接口接收其子类XmlBeanFactory类。
// 获取spring容器
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
使用BeanFactory和XmlBeanFactory和ClassPathResource获取Bean对象完整代码:
import com.spring.bean.Student;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;public class TeacherMain {public static void main(String[] args) {// 懒汉加载:调用时,才加载spring容器中的bean对象,效率不高,但是内存消耗低。BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));Student student = (Student) factory.getBean("student");student.wmi();}
}
法二:ApplicationContext接口和ClassPathXmlApplicationContext继承类
获取spring容器(使用ApplicationContext接收其子类ClassPathXmlApplicationContext,给ClassPathXmlApplicationContext传参配置文件的文件名)
// 获取Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
使用ApplicationContext接口和其子类ClassPathXmlApplicationContext获取Bean对象的完整代码:
import com.spring.bean.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class StudentMain {public static void main(String[] args) {// 饿汉加载:一次性加载并初始化spring配置文件中的对象,后续操作spring容器中的bean对象时会很快,但是费内存。// 1通过resources文件夹中的xml文件名,获取spring容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 2获取Bean对象Student student2 = context.getBean("student", Student.class);// 3使用spring bean对象student.wmi();}
}
2.2、getBean获取指定的Bean对象
getBean方法的参数,可以使用多种方式进行传参:
一,使用名称获取
二、使用类型获取,(如果存储两个名称不同,类型相同的对象,会找不到唯一的Bean,从而报错)
三、使用名称+类型获取(最保险,不容易出错)
2.3、获取Bean对象的名称的命名源码分析
在获取Bean对象时,Bean对象名是什么?
首先,为了突出重点,我们先直接亮出结论:
规律:
①:如果需要保存在spring中的对象所属的类 的首字母和第二个字母都大写,如(ACar->ACar),那么Bean对象的名字为原类名。使用context.getBean("原类名", 类名.class)
方式从spring中获取对象。
②:如果不是情况一,那就把首字母小写(如A->a,RedCar->redCar)。如要从spring中获取一个CarController使用context.getBean("carController", CarController.class)
获取CarController对象。
现在,我们查看spring源码,印证我们的结论:
A:操作:双击shift键,搜索BeanName,找到好几个类,因为我们是要找Bean的命名规则,根据Bean的命名英文推导,一个一个去找,我这里直接给出结论:双击shift键,搜索BeanName,出现下图,点击AnnotationBeanNameGenerator(注解BeanName生成类)。
B:点击左边的structure,弹出该类的各种方法。点击generatorBeanName方法。按住ctrl,点击下图中调用的方法。
C:在generatorBeanName方法中 ctrl+点击方法调用,跳转到BuildDefaultBeanName(参数一,参数二),在该方法中再次ctrl+点击方法调用跳转到它的重载函数BuildDefaultBeanName(参数)。再使用ctrl+点击方法调用,跳转到了最终的目的函数。
D:目的函数Introspector类的decapitalize方法中
注意: decapitalize方法中,传入的参数name是要存入spring的对象所属的类名。
如果传入的参数是null,或者参数长度为0,那么直接返回类名,代表这个存入spring的对象的名字是null或空字符串。
如果传入的参数长度大于1,且首字母和次首字母都是大写,那么直接返回类名,代表这个存入spring的对象的名字是原类名。
如果传入参数不是null,长度大于0,如果只有一个字母,将首字母小写返回。如果有多个字母,且首字母和第二个字母不都是大写,那就将原类名的第一个字母小写返回,作为存入spring的对象的名字。
E:结论: spring代码生成Bean对象的命名是使用jdk的标准起名的
看下图,在上面的操作C时,点击标出来的蓝色框定位当前类AnnotationBeanNamGenerator的位置,可以看到这个类是存在于spring源码中的。
操作C完成后,跳转到到Introspector类的decapitalize方法中,再寻找Introspector类的所在位置,如下图,它出现在了jdk的rt.jar中。
2、使用依赖注入从spring获取对象
注意:指在Controller的类中注入Service,在Service中注入Repository。学spring到目前为止暂时无法实现 在main方法所在的类中注入Controller,在main中只能使用getBean获取对象,后续在springboot中则不需要main方法,而是tomcat自动执行。
2.1、法一:属性注入
属性注入:
步骤A:加注解 @Autowired
步骤B:写要注入的类作为当前类的属性。
如下图:
属性注入优缺点:
优点:简单,易操作。
缺点:
1> 无法实现final修饰的变量的注入,如private final CarService carService
使用属性注入,无法成功注入;
2> 兼容性不足,只适用于IoC容器;
3> 易违反单一设计原则(注入多个对象,做多个功能)。
2.2、法二:setter注入
setter注入:
步骤A:要注入对象作为当前类的属性。
步骤B:注解@Autowired + set方法给要注入的对象赋值。(参数是自己从spring中取出来传给set方法作为参数)set注入的优缺点:
优点:严格遵循单一设计原则
缺点:
1> 无法实现final修饰的变量注入;
2> 注入的对象有被修改的风险,因为set方法是public修饰的。
2.3、法三:构造方法注入
构造方法注入:
步骤A:要注入对象作为当前类的属性。
步骤B:注解+构造方法给注入对象赋值。(参数是自己从spring中取出来传给构造方法作为参数)
构造方法注入优缺点:
优点:
1>可以实现final修饰变量的注入。(在Java中,final修饰的变量要么直接赋值,要么在构造方法中赋值,这是语法规定,因此构造方法可以实现final修饰变量的注入,而set方法无法实现)
2>注入对象无法被修改,因为构造方法只执行一次。
3> 构造方法注入可以保证注入对象被完全初始化。因为构造方法注入是对象实例化的过程中进行的,而属性注入和set注入是在对象实例化之后进行的。
4> 通用性更好,因为是Java语法规定,不仅仅适用于IoC容器。
补充:在依赖注入中 @Autowired和 @Resource的区别
问题1: @Autowired和 @Resource有时可以替换,有时不行,接下来分析它们的区别:
来源不同:@Autowired来自spring,@Resource来自JDK
使用范围不同:@Autowired可以适用于三种注入,@Resource只支持属性注入和set注入,不支持构造方法注入。
参数个数和类型不同:@Resource支持多个参数设置,适用于同一个类注入多个对象情况,对修改对象名字上更加灵活;@Autowired只有一个boolean类型的参数设置。
查找Bean对象方式不同:@Autowired先根据类型查找,后根据名称查找(注入变量的名称),ByType;@Resource先根据名称查找,后根据类型查找,ByName。
问题2:当存储了同类型的多个对象时,可以使用两种方式依赖注入对象。
1> @Resource参数的设置
2> @Autowired + @Qualifier(value=“对象名”)
相关文章:

【Spring】-Spring中Bean对象的存取
作者:学Java的冬瓜 博客主页:☀冬瓜的主页🌙 专栏:【Framework】 主要内容:往spring中存储Bean对象的三大方式:XML方式(Bean标签);五大类注解;方法注解。从spring中取对象的两种方式…...

机器人CPP编程基础-03变量类型Variables Types
机器人CPP编程基础-02变量Variables 全文AI生成。 C #include<iostream>using namespace std;main() {int a10,b35; // 4 bytescout<<"Value of a : "<<a<<" Address of a : "<<&a <<endl;cout<<"Val…...
或许有用的开源项目平台——物联网、区块链、商城、CMS、客服系统、低代码、可视化、ERP等
摘自个人印象笔记Evernote Export wumei-smart-物美智能开源物联网平台 官网:https://wumei.live/ gitee:https://gitee.com/kerwincui/wumei-smart 一个简单易用的物联网平台。可用于搭建物联网平台以及二次开发和学习。适用于智能家居、智慧办公、智慧…...

火车头采集伪原创插件【php源码】
大家好,小编来为大家解答以下问题,python代码大全和用法,python代码大全简单,现在让我们一起来看看吧! 火车头采集ai伪原创插件截图: 1、题目:列表转换为字典。 程序源代码: 1 #!/us…...

【数学】CF1514 C
Problem - 1514C - Codeforces 题意: 思路: Code: #include <bits/stdc.h>using i64 long long;constexpr int N 2e5 10; constexpr int M 2e5 10; constexpr int mod 998244353;void solve() {int n;std::cin >> n;std:…...

SqlServer基础之(触发器)
概念: 触发器(trigger)是SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发&#x…...

数据结构刷题训练:队列实现栈
目录 前言 1. 题目:使用队列实现栈 2. 思路 3. 分析 3.1 创建栈 3.2入栈 3.3 出栈 3.4 栈顶数据 3.5 判空和 “ 栈 ” 的销毁 4. 题解 总结 前言 我们已经学习了栈和队列,也都实现了它们各自的底层接口,那么接下我们就要开始栈和队列的专项刷…...

(统计学习方法|李航)第四章 朴素贝叶斯算法——贝叶斯估计
贝叶斯估计方法: 计算男女时只有两个值,所以K2 贝叶斯估计就是拉普拉斯平滑 估计方法:为什么叫做贝叶斯估计呢? 例题: 重新回顾以下朴素贝叶斯: 对他求导,求出最大值 得到了色i他的估计值&…...

企业直播MR虚拟直播(MR混合现实直播技术)视频介绍
到底什么是企业直播MR虚拟直播(MR混合现实直播技术)? 企业直播MR虚拟直播新玩法(MR混合现实直播技术) 我的文章推荐: [视频图文] 线上研讨会是什么,企业对内对外培训可以用线上研讨会吗&#x…...
React Fiber: 从 Reconciliation 到 Concurrent Mode
React Fiber 是 React 中的一种新的协调算法,它的主要目的是提高 React 的性能和可维护性。在 React Fiber 之前,React 使用了一种叫做 Stack Reconciliation 的算法来处理组件的更新和渲染。但是 Stack Reconciliation 存在一些问题,比如无法…...

【PostgreSQL内核学习(十一)—— OpenGauss源码学习(CopyTo)】
可优化语句执行 概述什么是列存储?列存的优势 相关函数CopyToCStoreCopyToCopyStatetupleDescCStoreScanDesc CStoreBeginScanRelationSnapshotProjectionInfo GetCStoreNextBatchRunScanFillVecBatchCStoreIsEndScan CStoreEndScan 声明:本文的部分内容…...

计算机网络 网络层 IPv4地址
A类地址第一位固定0 B类10 其下同理...
【程序员社交】多和高层次人群交流
定义问题:如何多和高层次人群交流获取经验提升自己? 收集信息:通过社交媒体、行业论坛、行业大会等途径获取高层次人群的信息和观点,并了解他们的工作经历、技能和能力。 分析信息:分析收集到的信息,了解…...
机器学习笔记 - 基于C++的深度学习 三、实现成本函数
机器学习中的建模 作为人工智能工程师,我们通常将每个任务或问题定义为一个函数。 例如,如果我们正在开发面部识别系统,我们的第一步是将问题定义为将输入图像映射到标识符的函数F(X)。但是问题是如何知道F(X)公式? 事实上,使用公式或一系列固有规则来定义F(X)是不可行的(…...

lazada、shopee店铺如何利用测评提高权重和排名?
在 lazada、shopee平台上开店后,卖家们必须对店铺的权重进行更多的关注。如果店铺的权重越高,那么它就会带来更多的流量和更多的订单,那么在 lazada、shopee平台上开设一家店铺,该怎样增加它的店铺权重和排名呢? laza…...

安全第二次
一,iframe <iframe>标签用于在网页里面嵌入其他网页。 1,sandbox属性 如果嵌入的网页是其他网站的页面,因不了解对方会执行什么操作,因此就存在安全风险。为了限制<iframe>的风险,HTML 提供了sandb…...
125、SpringBoot可以同时处理多少请求?
SpringBoot可以同时处理多少请求? 一、前言二、线程池4大参数图解三、代码示例一、前言 我们都知道,SpringBoot默认的内嵌容器是Tomcat,也就是我们的程序实际上是运行在Tomcat里的。所以与其说SpringBoot可以处理多少请求,到不如说Tomcat可以处理多少请求。 关于Tomcat的默…...

SSE技术和WebSocket技术实现即时通讯
文章目录 一、SSE1.1 什么是SSE1.2 工作原理1.3 特点和适用场景1.4 API用法1.5 代码实现 二、WebSocket2.1 什么是WebSocket2.2 工作原理2.3 特点和适用场景2.4 API用法2.5 代码实现2.6 心跳检测 三、SSE与WebSocket的比较 当涉及到实现实时通信的Web应用程序时,两种…...

什么是敏捷开发?
敏捷开发流程:制度化、规范化地PUA程序员的顶级神器!!!...
tcp发送整型,结构体等数据的方法
测试环境 Receiver: x86 UbuntuSender: arm64 android 发送整型数 C语言和套接字库来发送一个整型变量(int)的客户端程序。 它首先创建一个TCP套接字,然后连接到指定的服务器地址和端口。接着,它将一个整型变量(in…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
linux设备重启后时间与网络时间不同步怎么解决?
linux设备重启后时间与网络时间不同步怎么解决? 设备只要一重启,时间又错了/偏了,明明刚刚对时还是对的! 这在物联网、嵌入式开发环境特别常见,尤其是开发板、树莓派、rk3588 这类设备。 解决方法: 加硬件…...
后端下载限速(redis记录实时并发,bucket4j动态限速)
✅ 使用 Redis 记录 所有用户的实时并发下载数✅ 使用 Bucket4j 实现 全局下载速率限制(动态)✅ 支持 动态调整限速策略✅ 下载接口安全、稳定、可监控 🧩 整体架构概览 模块功能Redis存储全局并发数和带宽令牌桶状态Bucket4j Redis分布式限…...
Vue3学习(接口,泛型,自定义类型,v-for,props)
一,前言 继续学习 二,TS接口泛型自定义类型 1.接口 TypeScript 接口(Interface)是一种定义对象形状的强大工具,它可以描述对象必须包含的属性、方法和它们的类型。接口不会被编译成 JavaScript 代码,仅…...