内容很多可以通过目录进行查找对应的内容。
目录
[@RequestMapping 路由映射注解](#@RequestMapping 路由映射注解)
[@PathVariable 请求url路径中url的参数与方法参数的绑定](#@PathVariable 请求url路径中url的参数与方法参数的绑定)
[@RestController 和@Controller](#@RestController 和@Controller)
五大类注解和@Bean方法注解在下面有讲,可通过目录进行查找
[@Autowired 注解](#@Autowired 注解)
[四、Spring IOC&DI](#四、Spring IOC&DI)
[1)通过@Bean方法手动创建外部类的实例,将其注册为Spring Bean](#1)通过@Bean方法手动创建外部类的实例,将其注册为Spring Bean)
一、注解
元注解
元注解的作用就是负责注解其他注解,在其他注解的源码中可以看到元注解。常见的元注解有以下几种:
- @Retention:指定其所修饰的注解的保留策略。比如SOURCE值表示注解只在源文件中保留,编译期间删除;CLASS表示注解只在编译期间存在于.class文件中,运行时JVM不可获取注解信息。
- @Document:该注解是一个标记注解,用于指示一个注解将被文档化。
- @Target:用来限制注解的使用范围。值为Type表示可以修饰类,接口,注解或枚举类型;FIELD表示修饰属性;METHOD表示可以修饰方法。除了这些还有很多值。
- @Inherited:该注解使父类的注解能被其子类继承。
- @Repeatable:该注解是java8新增的注解,用于开发重复注解。
@RequestMapping 路由映射注解
这是一个用来处理请求"地址映射"的注解,可用于映射一个请求或一个方法,可以用在类和方法是上。
- 标注在方法上:
用于方法上,表示在父路径下追加方法上注解中的地址将会访问到该方法
- 标注在类上:
用于类上,表示类中的所有相应请求的方法都是以该地址作为父路径。
此外@RequestMapping支持get和post方法,所以在用该注解修饰方法时可以自己设置method属性:
@RequestMapping(value = "/sayhi/b",method = RequestMethod.GET)
@RequestParam绑定请求参数到可控制器方法的参数
请求参数绑定可控制方法参数:
java
@RequestMapping("/m6")
public String method2(@RequestParam List<String> list) {
return list.toString();
}
使用该注解,可以自动将HTTP请求中的同名多值参数绑定到该集合 ,若省略该注解,Spring不会自动绑定多值请求参数到该集合中,这会导致list为null或绑定失败,所以必须显式的添加该注解。
++但是控制器方法的参数为数组类型时,即使不显式的使用该注解,Spring也会默认将HTTP请求中的同名多值参数自动绑定到该数组中,这是和其他集合类不一样的地方。++
java
@RequestMapping("/m5")
public String method( String[] arraryParam){
return Arrays.toString(arraryParam);
}
++当然了,数组也可以显式的去添加该注解。++
java
@RequestMapping("/m5")
public String method(@RequestParam String[] arraryParam){
return Arrays.toString(arraryParam);
}
参数绑定重命名
某种情况下,前端传递的参数key和后端传送的参数key不一致,比如前端传递了一个time,而后端使用createtime来接收,这样后端就会出现参数收不到的情况,若出现这种情况,我们可以使用注解@RequestParam来重命名后端参数的值。
@RequestMapping("/m4")
public Object method_4(@RequestParam("time") String createtime) {
return "接收到参数createtime:" + createtime;
}
上面的代码中,前端传递了time的值,然后传递给后端的createtime,这样就能够保证前端和后端参数定义可以不一致。
若前端利用createtime进行传递,浏览器就会报错;并且用了该注解,该参数必须进行传递。
当然,我们可以设置属性,让该参数变成不必传的参数,即使不传或者key参数错误,返回的value值都是null。
java
@RequestMapping("/m4")
public Object method_4(@RequestParam("time",require =false) String createtime) {
return "接收到参数createtime:" + createtime;
}
- 传递错误的key:

- 不传递值:

@RequestBody请求正文注解
具体实现可以看 6. 传递JSON数据
意思是这个注解作用在请求正文的数据绑定,请求参数必须写在请求正文中,++即HTTP请求正文直接映射到方法的参数。++
java
@RequestMapping("/m7")
public Object method3(@RequestBody User user){
return user.toString();
}
@ResponseBody响应体正文注解
@ResponseBody既是类注解又是方法注解。这个注解用在类上表示该类的所有方法返回的都是数据;若作用在方法上,表示该方法返回的是数据。
这个注解的作用是方法的返回值作为响应体进行返回。
java
@ResponseBody
@RequestMapping("/user")
public String getUser() {
return "index.html"; // 返回视图名称(如 user-page.jsp)
}
@PathVariable 请求url路径中url的参数与方法参数的绑定
path variable:路径变量
这个注解主要作用在请求URL路径上的数据绑定
默认传递参数写在URL上,springMVC就可以通过数据绑定获取到该参数。
后端实现代码:
java
@RequestMapping("/m8/{id}/{name}")
public String method4(@PathVariable Integer id, @PathVariable String name){
return "解析参数id:"+id+",name:"+name;
}

同时我们可以对后端参数进行重命名,让前端参数和后端参数映射。
java
@RequestMapping("/m8/{id}/{name}")
public String method4(@PathVariable Integer id, @PathVariable("name") String username){
return "解析参数id:"+id+",name:"+username;
}
@RequestPart上传文件
是springmvc中用于处理多部分请求的注解,常用于文件上传、同时传递文件和其他结构化数据。
核心作用:
- 处理文件上传:绑定请求中的文件部分到MultipartFile类型的参数。
- 结构化数据:解析请求中的非文件部分到java对象,通常结合@RequestBody使用。
- 支持复杂请求:适用于需要同时上传文件和其他元数据的场景(上传用户头像并附带用户信息)。
java
@RequestMapping("/m9")
public String getFile(@RequestPart("file") MultipartFile file) throws IOException {
//获取文件名称
String filename = file.getOriginalFilename();
//文件上传到指定路径
file.transferTo(new File("D:/Postman/"+filename));
return "接收到的文件名称为"+filename;
}
使用postman发送请求:

@RestController 和@Controller
这两个注解有本质的区别,导致两者在返回结果时表现不同。
@Controller
本质是传统的Spring MVC控制器,Spring框架启动时加载,把这个对象交给Spring进行管理。
用法**:用于处理客户端发起的请求,并负责返回适当的视图(view)作为响应** ,即方法默认返回视图名称(需配合视图解析器解析为HTML/JSP等页面)。

java
@RequestMapping("/user")
public String getUser() {
return "/index.html"; // 返回视图名称(如 user-page.jsp)
}
页面展示结果:

++其中,项目文件中要有对应的视图文件(index.html),若没有会返回404错误;并且该方法的类是引用@Controller这个注解的。++
@RestController
本质是@Controller和@ResponseBody的组合注解。
用法:在使用**@RestController注解标记的类中,每个方法的返回值都会以JSON或xml的形式直接写入HTTP响应体中,即** 所有方法默认返回数据(如JSON、xml),而非视图名称。
java
@RequestMapping("/user")
public String getUser() {
return "/index.html"; // 返回视图名称(如 user-page.jsp)
}

++其中该代码使用了@RestController注解,访问页面中会显示/index.html。++
五大类注解和@Bean方法注解在下面有讲,可通过目录进行查找
@Autowired 注解
需要搭配类级别的Spring管理注解使用,因为它的核心机制依赖于Spring容器来管理Bean的创建和依赖注入,所以被@Autowired注入的类必须被Spring容器管理。
二、请求学习:
请求的学习主要是学习如何传递参数
1.传递单个参数
2.传递多个参数
参数如果使用基本数据类型必须要传递值,不传递就会报错,所以开发时建议使用包装类型
3.传递对象
如果有很多形参时,就要传递很多参数,并且后续每增加一个参数,也需要修改方法声明,那么我们可以把这些参数封装成一个对象。
这样我们可以通过URL填写参数值,queryString的参数key与类型值要与后端的属性名要一致 ,如果属性类型是包装类型,queryString参数key和后端属性名不一致的话,返回的结果是null,若属性是基本类型,querystring参数key和后端参数的名不一致的话,返回就会报错。
4.传递数组
当请求参数名与形参数组名称相同且请求参数为多个,后端定义数组类型形参即可接收参数。
java
@RequestMapping("/m5")
public String method(String[] arraryParam){
return Arrays.toString(arraryParam);
}

其中url还可以为:
http://127.0.0.1:8080/s/m5?arraryParam=zhangsan\&arraryParam=lisi
或者http://127.0.0.1:8080/s/m5?arraryParam=zhangsan%2Clisi%2Cwangwu
5.传递集合
集合参数:和数组类似,同一个请求参数名有多个,且需要使用@RequestParam绑定参数关系。
默认情况下,请求中参数名相同的多个值,是封装到数组。如果要封装到集合,要使用@RequestParam绑定参数关系。
其中url的请求方式和数组类似。
java
@RequestMapping("/m6")
public String method2(@RequestParam List<String> list){
return list.toString();
}

6.传递JSON数据
**JSON概念:**JavaScript Object Notation,即JavaScript对象表示法。
JSON是一种轻量级的数据交互格式,它基于ECMAScript的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简单来说:JSON就是一种数据格式,有自己的格式和语法,使用文本表示一个对象或数组的信息,因此JSON本质是字符串。主要负责在不同语言中数据传递和交换。
JSON和JavaScript的关系:
两者没有关系,只是语法相似,js开发者能更快的上手而已,但是他的语法本身比较简单,所以很好学。
JSON的语法:
- 数据在键值对(key/value)中
- 数据由逗号,分割
- 对象用{}表示
- 数组用[ ]表示
- 值可以为对象,也可以为数组,数组中可以包含多个对象。
下面可以看一段JSON数据:
javascript
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": ["Radiation resistance", "Turning tiny", "Radiation
blast"]
}, {
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": ["Million tonne punch", "Damage resistance", "Superhuman
reflexes"]
}, {
"name": "Eternal Flame",
"age": 1000000,
"secretIdentity": "Unknown",
"powers": ["Immortality", "Heat Immunity", "Inferno",
"Teleportation", "Interdimensional travel"]
}]
}
JSON的两种结构:
对象:用大括号{}保存的对象是一个无序的键值对集合,一个对象以左括号{开始,右括号}结束。每个键后跟一个冒号:,键值对使用逗号,分隔。
数组:中括号 [ ] 保存的数组是值(value)的有序集合。一个数组以左中括号[开始,右中括号]结束,值之间使用逗号,分隔。
JSON和java对象互转
JSON本质上是一个字符串,通过文本来存储和描述数据
SpringMVC框架也集成了JSON转换工具,我们可以直接使用来完成JSON字符串和java对象的互转。
springmvc已经把转换的依赖引进来了,所以不用再去官网上去找依赖并引进去。
JSON优点:
简单易用;跨语言支持;轻量级,占用宽带小;易于扩展,支持嵌套对象和数组;安全性好,JSON格式是一种纯文本格式不会执行恶意代码。
传递JSON对象:
接收JSON对象需要使用@RequestBody注解。
RequestBody:请求正文,意思是这个注解作用在请求正文的数据绑定,请求参数必须写在请求正文中(body)。
后端实现:
java
@RequestMapping("/m7")
public Object method3(@RequestBody User user){
return user.toString();
}
利用postman来发送JSON请求参数:

响应结果:

7.从URL中获取参数
从URL获取参数是利用注解@PathVariable
java
@RequestMapping("/m8/{id}/{name}")
public String method4(@PathVariable Integer id, @PathVariable("name") String username){
return "解析参数id:"+id+",name:"+username;
}
8.通过请求上传文件
后端实现:
java
@RequestMapping("/m9")
public String getFile(@RequestPart("file") MultipartFile file) throws IOException {
//获取文件名称
String filename = file.getOriginalFilename();
//文件上传到指定路径
file.transferTo(new File("D:/Postman/"+filename));
return "接收到的文件名称为"+filename;
}
9.获取Cookie/Session
关于cookie和session的内容可以看这篇博客:session和cookie
获取Cookie
由于Spring MVC是基于Servlet API构建的原始Web框架,也是在Servlet的基础上实现的。
所以我们可以更简单的获取Cookie。
java
@RequestMapping("/getcookie")
public String cookie(@CookieValue("bite") String bite){
return "bite:"+bite;
}
利用@CookieValue这个注解让参数"bite"与浏览器中的名称bite进行绑定然后获取对应的value值。

获取Session
通过Spring MVC内置对象HttpSession来获取。
java
@RequestMapping("/getSession")
public String getSession(HttpSession session){
session.setAttribute("name","java");
String name = (String)session.getAttribute("name");
return "name:"+name;
}
Session不存在的情况下,创建session对象并存储信息。
此时创建session对象,服务器会返回携带有sessionID的cookie并存储到浏览器中。

10.获取Header
通过Spring MVC框架简洁获取Header。
java
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String userAgent){
return "userAgent" + userAgent;
}
@RequestHeader注解的参数值为HTTP请求报头中的"Key"

三、响应学习
http响应结果可以是数据,也可以是静态页面内,也可以针对响应设置状态码,Header信息等。
1.返回静态页面
创建前端页面index.html

html代码如下:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index⻚⾯</title>
</head>
<body>
Hello,Spring MVC,我是Index⻚⾯.
</body>
</html>
后端代码:
java
//类路径为 /s
@RestController
public class IndexController {
@RequestMapping("/index")
public Object index(){
//返回index.html
return "/index.html";
}
}
输入:http://127.0.0.1:8080/s/index
得到的结果为:

结果发现,页面未能正确返回,http响应把"/index.html"当做了http响应正文的数据。为了让springmvc能识别出index.html是一个静态页面并返回响应,我们把@RestController改为@Controller即可:
java
@Controller
public class IndexController {
@RequestMapping("/index")
public Object index(){
return "/index.html";
}
}
再次输入刚刚的url即可访问该静态页面:

2.返回数据@ResponseBody
该注解是把返回的数据通过响应体进行返回。
由于@RestController是@Controller和@ResponseBody的结合,那么我们可以这样子:
java
@Controller
public class IndexController {
@RequestMapping("/index")
public Object index(){
return "/index.html";
}
@RequestMapping("/returnData")
@ResponseBody
public String returnData(){
return "该⽅法返回数据";
}
}
再次运行程序,浏览器响应结果为:

若去掉@ResponseBody,程序会报404错误。
java
@Controller
public class IndexController {
@RequestMapping("/index")
public Object index(){
return "/index.html";
}
@RequestMapping("/returnData")
@ResponseBody
public String returnData(){
return "该⽅法返回数据";
}
}
程序中就只剩下了@Controller,程序就会认为返回的是视图,根据内容去查找文件,但是查询不到,路径不在,报404.。

3.返回HTML代码片段
若后端返回数据时,如果数据中有HTML代码,也会被浏览器解析。
java
@RequestMapping("/returnHtml")
@ResponseBody
public String returnHtml() {
return "<h1>Hello,HTML~</h1>";
}

++响应体(body)的类型(Content-Type)为text/html。++
如果返回的代码片段是js,SpringMVC会自动设置++Content-Type 为++application/javascript。
如果请求的是css⽂件, Spring MVC会⾃动设置Content-Type为 text/css。
但是要配合上@Controller注解以及要有js文件和css文件。
java
@RequestMapping("/index2")
public Object index2(){
return "/a.js";
}
@RequestMapping("/index3")
public Object index3(){
return "/b.css";
}

抓包结果:


4.返回JSON
当方法返回的是对象时,content-type自动设置为application/json。
java
@RequestMapping("returnJson")
public User returnJson(User user){
return user;
}

可以看到,返回的响应体为JSON格式的。
5.设置状态码
springmvc会根据我们方法的返回结果自动设置响应状态码,当然我们也可以手动指定状态码,通过springmvc的内置对象 HttpServletResponse 提供的方法来进行设置。
四、Spring IOC&DI
1.IOC(控制反转)的核心思想
什么是IOC?
IOC(Inversion of Control)是一种设计原则,其++核心思想是将对象的创建、依赖管理和生命周期的控制权交给一个容器(IOC容器)++,而不是由对象自身直接控制。
- 传统方式:对象主动创建和管理依赖(如new UserService() ),导致类之间高度耦合。
- IOC方式:由容器统一创建和管理对象,对象只需声明需要哪些依赖,容器负责注入到类中。
IOC容器的核心作用
创建对象:根据配置或注解,实例化类并管理其生命周期。
管理依赖关系:自动处理对象之间的依赖(如A类需要B类的实例)。
2.DI(依赖注入):IOC的具体实现技术
什么是依赖?
如果一个类需要另一个类的实例才能完成功能,则称其依赖这个类。
例如:++底盘依赖于车身,底盘是依赖方,车身是被依赖方,看下面的代码中,需要把底盘这个依赖注入到车身的类中。++


这是控制反转的一个简单的例子。
什么是依赖注入(DI)?
DI(Dependecy Injection)是实现++IOC的具体技术,++通过将依赖对象的实例从外部(IOC容器)注入到目标对象中,而非由目标对象自己创建。
- 核心思想:对象的依赖关系由外部提供,而不是内部硬编码。
- 关键角色:IOC容器负责创建依赖对象并注入到需要的位置。
常见的依赖注入方式
|----------|-------------------|
| 方式 | 描述 |
| 构造器注入 | 通过构造函数传递依赖对象 |
| Setter注入 | 通过Setter方法设置依赖对象 |
| 属性注入 | 直接通过字段(属性)的方式注入依赖 |
三种注入优缺点分析:
- 属性注入:
属性注入的流程如下:
1.实例化对象,先调用类的默认无参构造器创建对象。
2.反射注入字段:通过反射机制直接对字段赋值。
优点:
简洁,使用方便。
缺点:
只用用于IOC容器,如果非IOC容器就不可以了,并且只有在使用的时候才会出现NPE(空指针异常)。
不能注入一个Final属性。
理由:Final字段必须在构造期间完成初始化,但是属性注入是在对象构造完后通过反射赋值,根据依赖注入的流程,无法满足final的要求。
java
@Service
public class UserService {
public void sayHi() {
System.out.println("Hi,UserService");
}
}
@Controller
public class UserController {
//注⼊⽅法1: 属性注⼊
@Autowired
private UserService userService;
public void sayHi(){
System.out.println("hi,UserController...");
userService.sayHi();
}
}
若把 @Autowired注解去掉,就会报出空指针异常,spring不会自动创建该实例并进行赋值,因此,userService属性保持null值。
- 构造函数注入:
构造器注入流程如下:
- 实例化对象:Spring直接调用有参构造器创建对象,不需要默认无参构造器。
- 注入依赖:依赖参数在构造器调用你时直接传入(无需后续反射赋值)。
优点:
可以注入final修饰的属性,注入的对象不会被修改,满足final的要求。
依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的。
通用性好,构造方法是JDK支持是、的,所以更换任何框架,他都是适用的。
缺点:
注入多个对象时,代码会比较繁琐。
java
@Service
public class UserService {
public void sayHi() {
System.out.println("Hi,UserService");
}
}
public class UserController {
private final UserService userService;
@Autowired
// 构造器注入:依赖字段是 final 的
public UserController(UserService userService) {
this.userService = userService;
}
}
注意事项:如果类只有一个构造方法,那么 @Autowired注解可以省略;如果类中有多个构造方法,那么需要添加上@Autowired来明确到底要使用哪个构造方法。
- Setter注入:
Setter依赖注入流程:
- 实例化对象:调用默认无参构造器创建对象。
- 反射调用setter方法:通过反射调用Setter方法注入依赖。
优点:
方便在类实例之后,重新对该对象进行配置或者注入。
缺点:
不能注入一个Final修饰的属性。
注入对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险。
java
@Service
public class UserService {
public void sayHi() {
System.out.println("Hi,UserService");
}
}
@Controller
public class UserController3 {
//注⼊⽅法3: Setter⽅法注⼊
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
若把@Autowired注解去掉,同属性注入一样,spring默认不会自动调用setter方法进行注入,因此
userService
字段会保持null,后续调用的方法userService.sayHi()
时抛出空指针异常。
3.Spring框架中的核心概念:Bean注解
Bean是什么?
定义:由spring IOC容器管理的对象称为Bean。
生命周期:Bean的创建、初始化、依赖注入和销毁均为容器控制。
五大类注解和方法注解
类注解:标记Bean的角色
Spring通过注解标记类,告诉容器哪些类需要被管理为Bean,并明确角色:
|----------------|---------------------------------|
| 注解 | 用途 |
| @Component | 通过注解,标记任意类为Bean |
| @Controller | 标记为Web控制器(处理HTTP请求) |
| @Service | 标记业务逻辑层组件 |
| @Repository | 标记为数据访问层组件(DAO)(自动处理数据库异常转换) |
| @Configuration | 标记为配置类(定义Bean的创建方式,常与@Bean配合使用) |
++在Spring中,五大核心注解虽然最终都能将类注册为Spring Bean ,但它们设计的目的是为了区分代码的分层和职责,比如要在业务逻辑层使用@Component或@Service,很显然@Service是更好的选择。此外,这些注解还在功能上存在细微的差异,并非完全一样。++
++差异体现:++
|----------------|----------------------------------------------------------------|
| 注解 | 特殊行为 |
| @Component | 无特殊行为 |
| @Controller | @Controller注解的类通常与@RequestMapping,@GetMapping等注解配合使用,处理HTTP请求。 |
| @Service | 无特殊行为,但强调业务逻辑的封装 |
| @Repository | 自动转换数据访问异常为Spring异常 |
| @Configuration | 标记类为配置类,配合@Bean使用 |
我们可以查看注解源码:

可以看到,这些注解里面都有一个注解@Component,说明它们本身就是属于@Component的"子类"。这些注解被称为@Component的衍生注解。
方法注解@Bean:定义Bean的创建逻辑
@Bean 核心功能:
++在Spring配置类中,通过@Bean注解的方法手动显式的创建对象,并将对象交给Spring 容器管理(成为Spring Bean)。++
|-------|----------------------------------------------|
| 注解 | 用途 |
| @Bean | 在配置类中标注方法,表示该方法返回一个Bean(用于定义第三方库组件的创建方式) |
@Bean方法注解要搭配类注解进行使用。
java
@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
}
补充:无论目标类是否有Spring注解,只要通过@Bean方法返回其实例,Spring就会管理该对象。比如上面的代码中,尽管UserRepository类没有被@Component这样的注解所标记,但是仍然能通过@Bean方法注册,Spring会直接使用该方法返回的实例。
但是目标类同时有@Component和@Bean时,Spring就会通过注解@Component扫描和@Bean方法注册,Spring就会报错,
我们知道类注解是添加到某个类上的,但是存在两个问题:
- 1.当使用第三方库或外部依赖包中的类时,是无法直接修改其源码添加Spring注解(如@Component);
- 2.一个类,需要多个对象,比如多个数据源。
++像这种场景,就需要可以使用方法注解@Bean来解决了++。
1)通过@Bean方法手动创建外部类的实例,将其注册为Spring Bean
java
@Configuration
public class ExternalConfig {
// 将外部类 Gson 注册为 Bean
@Bean
public Gson gson() {
return new Gson(); // 手动创建实例
}
}
在配置类中,通过@Bean来获得外部依赖类的实例。
2)定义多个对象的处理方法
对于同一个类,如何定义和获取多个对象呢?
比如多个数据源的场景,类是同一个,但是配置不同,指向不同的数据源。
我们看下@Bean的使用
java
@Component
public class BeanConfig {
@Bean
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User user2(){
User user = new User();
user.setName("lisi");
user.setAge(19);
return user;
}
}
定义了多个对象的话,根据类型获取对象,获取的是哪个对象呢?
java
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context =
SpringApplication.run(SpringIocDemoApplication.class, args);
//从Spring上下⽂中获取对象
User user = context.getBean(User.class);
//使⽤对象
System.out.println(user);
}
}
运行结果:

从上面的报错信息显示:期望只有一个匹配,结果发现了两个,user1,user2.
从报错信息中可以看出来,被@Bean注解的Bean的名称正是对应的方法名。
下面我们根据名称来获取bean对象
java
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context =
SpringApplication.run(SpringIocDemoApplication.class, args);
//根据bean名称, 从Spring上下⽂中获取对象
User user1 = (User) context.getBean("user1");
User user2 = (User) context.getBean("user2");
System.out.println(user1);
System.out.println(user2);
}
}
运行结果:

++可以看到,@Bean可以针对同一个类,定义多个对象。++
下面是解决同一类型中有多个对象时的解决方法:
通过重命名Bean或指定名称
可以通过设置name属性给Bean对象进行重命名操作:
java
@Bean(name = {"u1","user1"})
public User user1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
此时我们可以使用重命名后的u1这个名称来获得Bean对象了。
java
User u1 = (User) context.getBean("u1");
当然,name={}可以省略,如下:
java
@Bean({"u1","user1"})
只有一个名称时,{}也是可以省略的。
java
@Bean("u1")
Bean名和方法名一致
以下是完整代码:
java
@Configuration
public class A {
@Bean
public User User1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User User2(){
User user = new User();
user.setName("zhangsi");
user.setAge(10);
return user;
}
}
@Data
public class User {
private String name;
private Integer age;
}
@SpringBootApplication
public class Demo14Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Demo14Application.class, args);
User user1 = (User) context.getBean("User1");
User user2 = (User) context.getBean("User2");
System.out.println(user1);
System.out.println(user2);
}
}
运行结果:

使用@Primary注解标识默认对象
java
@Primary
@Bean
public User User1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
使用@Primary注解,表示让Spring默认匹配该对象。
使用@Qualifier
使用@Qualifier注解:指定当前要注入的bean对象。在@Qualifier的value属性中,指定注入的bean的名称。
比如在属性注入中@Qualifier注解不能单独使用,必须配合@Autowired使用。
java
@Qualifier("User1")
@Autowired
private User user1;
属性注入中指定了对应的Bean对象(即有方法返回对应名称(User1)的Bean对象,没有会报错)。
java
@Bean
public User User1(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
**代码解读:**注入了指定名称的User1的Bean对象。
使用@Resource注解标注名称注入对应名称的@Bean
使用方法:
java
@Resource(name = "User1")
private User user1;
@Resource这个注解和@Autowire有点像,但是还是有区别的。
@Autowire和@Resource的区别:
- @Autowire是Spring框架提供的注解,而@Resource是JDK提供的注解。
- @Autowire默认是按照类型注入,而@Resource是按照名称注入,相比于@Autowire来说,@Resource支持更多的参数设置,例如根据Bean的name来获得想要的Bean。
补充:Bean的命名规则
1)五大注解存储的bean
- 前两位字母均为大写,bean名称为类名,比如SEvice类,bean的名称就为 SEvice。
- 其他的类为类名首字母小写,比如Service,bean的名称为service;service,bean的名称为service。
- 可以通过value属性设置@Controller(value="user")
2)@Bean注解存储的bean
- bean名称为方法名。
- 通过name属性设置@Bean(name={"u1","user1"})。
扫描路径
使用前面的学习的类注解去声明bean,一定会生效吗?
不一定!!
默认的的扫描范围是Springboot启动类所在的包里面。
如果不在启动类所在的包里面可以在配置类上添加@ComponentScan注解,该注解默认会扫描该类所在包下的所有的配置类。