SpringIoCDI
目录
1.前情摘要
1.1 什么是Spring?
1.2 什么是容器?
1.3 什么是Ioc
2.Ioc
2.1 传统设计思想
2.2 解决方案
3.DI介绍
4.IoC和DI的使用
4.1 图书管理代码修改
4.2 依赖注入体现
5.IoC详解
5.1 Bean的存储
5.1.1 @Controller(控制器存储)
5.1.2 @Service(服务存储)
5.1.3 @Repository(仓库存储)
5.1.4 @Component(组件存储)
5.1.5 @Configuration(配置存储)
5.1.7 为什么要分这么多注解
5.2 方法注解@Bean
5.2.1 Bean命名规则
5.2.2获取Bean对象的方式
5.2.3 重命名Bean
5.3 两类注解对比
5.3.1类注解(@Component 全家桶)
5.3.2方法注解(@Bean)
5.3.3核心区别
5.3.4协作关系
5.3.5一句话总结
5.4 扫描路径
6.DI 详解
6.1 属性注入
6.2 构造方法注入
6.3 Setter注入
6.4 三种注解优缺点分析
6.5 @Autowired存在的问题
6.5.1 @Primary
6.5.2 @Qualifier
6.5.3 @Resource
7.总结
7.1 Spring,Spring Boot和Spring MVC的关系及区别
7.2 Bean的命名
7.3 常见面试题
1.前情摘要
1.1 什么是Spring?
Spring是⼀个开源框架,他让我们的开发更加简单.他支持广泛的应用场 景,有着活跃而庞大的社区,这也是Spring能够长久不衰的原因.
Spring是包含了众多工具方法的loC容器
1.2 什么是容器?
容器是用来容纳某种物品的(基本)装置。一来自:百度百科
生活中的水杯,垃圾桶,冰箱等等这些都是容器。
我们想想,之前课程我们接触的容器有哪些?
-
List/Map->数据存储容器
-
Tomcat -> Web 容器
1.3 什么是Ioc
在前面讲到,在类上面添加@RestController
和 @Controller
注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交 给Spring管理,就是IoC思想.
IoC:Inversion of Control(控制反转),也就是说Spring是一个"控制反转"的容器.
什么是控制反转呢?也就是控制权反转.什么的控制权发生了反转?获得依赖对象的过程被反转了
也就是说,当需要某个对象时,传统开发模式中需要自己通过new创建对象,现在不需要再进行创
建,把创建对象的任务交给容器,程序中只需要依赖注入(DependencyInjection,DI)就可以了.
这个容器称为:loC容器.Spring是一个loC容器,所以有时Spring也称为Spring容器.
控制反转是一种思想,在生活中也是处处体现
比如自动驾驶,传统驾驶方式,车辆的横向和纵向驾驶控制权由驾驶员来控制,现在交给了驾驶自
动化系统来控制,这也是控制反转思想在生活中的实现
比如招聘,企业的员工招聘,入职,解雇等控制权,由老板转交给给HR(人力资源)来处理
2.Ioc
2.1 传统设计思想
先设计轮子(Tire),然后根据轮子的大小设计底盘(Bottom),接着根据底盘设计车身(Framework),最后根据车身设计好整个汽车(Car)。这里就出现了一个"依赖”关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子.
public class NewCarExample {public static void main(String[] args) {Car car = new Car(20);car.run();}/*** 汽车对象 */static class Car {private Framework framework;public Car(int size) {framework = new Framework(size);System.out.println("Car init....");}public void run(){System.out.println("Car run...");}}/*** 车⾝类 */static class Framework {private Bottom bottom;public Framework(int size) {bottom = new Bottom(size);System.out.println("Framework init...");}}/*** 底盘类 */static class Bottom {private Tire tire;public Bottom(int size) {this.tire = new Tire(size);System.out.println("Bottom init...");}}/*** 轮胎类 */static class Tire {// 尺寸private int size;public Tire(int size){this.size = size;System.out.println("轮胎尺⼨:" + size);}}
}
从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调用链上的所有代码都需要修改.
程序的耦合度非常高(修改一处代码,影响其他处的代码修改)
2.2 解决方案
在上面的程序中,我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改,同样因为我们是根据底盘设计的车身,那么车身也得改,同理汽车设计也得改,也就是整个设计几乎都得改
我们尝试换一种思路,我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘来设计轮子.这时候,依赖关系就倒置过来了:轮子依赖底盘,底盘依赖车身,车身依赖汽车
我们可以尝试不在每个类中自己创建下级类,如果自己创建下级类就会出现当下级类发生改变操作,自己也要跟着修改.此时,我们只需要将原来由自己创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修改任何代码,这样就完成了程序的解耦
public class IocCarExample {public static void main(String[] args) {Tire tire = new Tire(20);Bottom bottom = new Bottom(tire);Framework framework = new Framework(bottom);Car car = new Car(framework);car.run();}static class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init....");}public void run() {System.out.println("Car run...");}}static class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("Framework init...");}}static class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("Bottom init...");}}static class Tire {private int size;public Tire(int size) {this.size = size;System.out.println("轮胎尺寸:" + size);}}
}
从上面也可以看出来,IoC容器具备以下优点:
汽车建造各个零件对外进行外包,我不需要关心实现的细节,只需要提对应的要求即可
资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。
-
资源集中管理:IoC容器会帮我们管理一些资源(对象等),我们需要使用时,只需要从IoC容器中去取就可以了
-
我们在创建实例的时候不需要了解其中的细节,降低了使用资源双方的依赖程度,也就是耦合度
Spring就是一种loC容器,帮助我们来做了这些资源管理.
依赖注入体现
3.DI介绍
DI: Dependency Injection(依赖注入)
容器在运行期间,动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。
程序运行时需要某个资源,此时容器就为其提供这个资源。
从这点来看,依赖注入(DI)和控制反转(IoC)是从不同的角度的描述的同一件事情,依赖注入是
从应用程序的角度来描述,就是指通过引入loC容器,利用依赖关系注入的方式,实现对象之间的解
耦.
上述代码中,是通过构造函数的方式,把依赖对象注入到需要使用的对象中的
loC是一种思想,也是"目标",而思想只是一种指导原则,最终还是要有可行的落地方案,而DI就属于
具体的实现。所以也可以说,DI是IoC的一种实现.
比如说我今天心情比较好,吃一顿好的犒劳犒劳自己,那么"吃一顿好的”是思想和目标(是
loC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是DI。
4.IoC和DI的使用
4.1 图书管理代码修改
Spring是一个IoC(控制反转)容器,作为容器具备的两个最基础的功能就是存和取
Spring容器管理的主要是对象,这些对象称之为"Bean",我们把这些对象交由Spring来管理,由Spring来负责对象的创建和销毁,我们程序只需要告诉Spring,哪些需要寸,以及如何从Spring中取出对象
-
Service层及Dao层的实现类,交给Spring管理:使用注解:@Component
-
在Controller层和Service层注入运行时依赖的对象:使用注解@Autowired
package com.example.demo.controller;import com.example.demo.model.BookInfo;
import com.example.demo.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;//控制层:接收前端发送的请求,对请求进行处理,并响应数据//获取图书列表
@RequestMapping("/book")
@RestController
public class BookController {@Autowired//从Spring中取出对象放入private BookService bookService;//依赖注入@RequestMapping("/getList")public List<BookInfo> getList(){//获取数据List<BookInfo> books = bookService.getBookList();return books;}
}
把 BookService
类标记为 Spring 管理的组件(Bean),交给Spring管理
@Component
注解在这里就是让 BookService
能被 Spring 容器识别和管理,成为整个 Spring 依赖注入、组件管理体系中的一部分,这样后续才能顺利进行 BookService
自身的依赖注入(比如注入 BookDao
),以及被其他组件(比如 BookController
)依赖注入使用 。
package com.example.demo.service;import com.example.demo.model.BookInfo;
import com.example.demo.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.List;
//业务逻辑层:处理具体的业务逻辑。
@Component
public class BookService {@Autowiredprivate BookDao bookDao;public List<BookInfo> getBookList(){//获取数据List<BookInfo> books = bookDao.mockData();//处理页面展示for(BookInfo book:books){if(book.getStatus() == 1) {book.setStatusCN("可借阅");}else{book.setStatusCN("不可借阅");}}return books;}
}
package com.example.demo.dao;import com.example.demo.model.BookInfo;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
//数据访问层:负责数据访问操作,包括数据的增、删、改、查
@Component
public class BookDao {public List<BookInfo> mockData() {List<BookInfo> books = new ArrayList<>();for (int i = 0; i < 10; i++) {BookInfo book = new BookInfo();book.setId(i);book.setBookName("书籍" + i);book.setAuthor("作者" + i);book.setCount(i * 5 + 3);book.setPrice(new BigDecimal(new Random().nextInt(100)));book.setPublish("出版社" + i);book.setStatus(1);books.add(book);}return books;}
}
4.2 依赖注入体现
@Autowired
private BookService bookService;
依赖注入就体现在借助@Autowired
,让 Spring 自动把BookService
的实例给BookController
的bookService
字段,不用自己手动创建,实现了对象依赖的 “自动装配” 。
@Autowired
private BookDao bookDao;
这段代码里依赖注入体现在通过 @Autowired
注解,让 Spring 容器自动为 BookService
类注入 BookDao
的实例,解耦了 BookService
和 BookDao
之间的对象创建依赖关系,符合 Spring 框架依赖注入的设计思想,让代码更易于维护和扩展(比如更换 BookDao
的实现类时,在一定程度上不用改动 BookService
的代码 )。
5.IoC详解
5.1 Bean的存储
交给Spring管理的类
两类注解:
-
类注解:@Controller,@Service,@Repository,@Component,@Configuration
-
方法注解:@Bean
注解加在类上,告诉 Spring:“这个类是一个组件(Bean),需要被扫描并纳入容器管理”。 (Spring 扫描到以上五大注解后,创建 UserService
的实例,其他组件可通过 @Autowired
注入。)
@Bean
加在方法上,告诉 Spring:“这个方法返回的对象需要注册为 Bean”。
5.1.1 @Controller(控制器存储)
package com.example.demo.controller;import org.springframework.stereotype.Controller;@Controller //将对象存储到Spring中
public class UserController {public void say(){System.out.println("UserController say...");}
}
从Spring容器中获取对象
package com.example.demo;import com.example.demo.controller.UserController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class Demo2Application {public static void main(String[] args) {//获取Spring上下文对象ConfigurableApplicationContext context = SpringApplication.run(Demo2Application.class, args);//从Spring上下文中获取对象UserController userController = context.getBean(UserController.class);//使用对象userController.say();}}
SpringApplication.run()
方法:
作用:启动SpringBoot应用,创建并返回一个Spring应用上下文(ApplicationContext)
执行流程:
-
创建一个Spring应用上下文(相当于一个"Bean容器")
-
扫描并注册所有被@Component等注解标记的类为Bean
-
自动配置Spring环境(如数据库连接,web服务器等)
-
启动嵌入式Web服务器(如果是Web应用)
-
返回上下文对象,用于后续操作
UserController userController = context.getBean(UserController.class);
作用:从Spring上下文中获取UserController类型的Bean
关键点:
-
UserController必须被Spring管理(如添加@Controller注解)
-
Spring会返回一个已经初始化并注入依赖的单例Bean
-
等价于在其他 Bean 中使用
@Autowired
注入UserController
。
5.1.2 @Service(服务存储)
package com.example.demo.service;import org.springframework.stereotype.Service;@Service
public class UserService {public void say(){System.out.println("UserService say...");}
}
UserService userService = context.getBean(UserService.class);
UserService userService3 =(UserService) context.getBean("userService");
UserService userService2 = context.getBean("userService", UserService.class);
5.1.3 @Repository(仓库存储)
@Repository
public class UserRepository {public void say(){System.out.println("UserRepository say...");}
}
5.1.4 @Component(组件存储)
@Component
public class UserComponent {public void say(){System.out.println("UserComponent say...");}
}
5.1.5 @Configuration(配置存储)
@Configuration
public class UserConfiguration {public void say(){System.out.println("UserConfiguration say...");}
}
5.1.7 为什么要分这么多注解
与应用分层是呼应的,让程序员看到类注解之后,就能直接了解当前类的用途,
-
@Controller:控制层,接收请求,对请求进行处理,并进行响应.
-
@Servie:业务逻辑层,处理具体的业务逻辑.
-
@Repository:数据访问层,也称为持久层.负责数据访问操作
-
@Configuration:配置层.处理项目中的一些配置信息.
类注解之间的关系
查看@Controller /@Service /@Repository /@Configuration 等注解的源码发现:
其实这些注解里面都有一个注解@Component
,说明它们本身就是属于@Component
的"子类".
@Component
是一个元注解,也就是说可以注解其他类注解,如@Controller,@Service
@Repository
等.这些注解被称为aComponent的衍生注解.
@Controller
,@Service和@Repository用于更具体的用例(分别在控制层,业务逻辑层,持
久化层),在开发过程中,如果你要在业务逻辑层使用@Component
或@Service
,显然@Service是更
好的选择
5.2 方法注解@Bean
5.2.1 Bean命名规则
UserController->userCotroller
UController->UController
5.2.2获取Bean对象的方式
UserController userController = context.getBean(UserController.class);
UserController userController2 = (UserController)context.getBean("userController");
UserController userController3 = context.getBean("userController", UserController.class);
方式 | 优点 | 缺点 | 典型场景 |
getBean(Class) | 无需记名称,类型安全 | 无法区分同类型不同名称的 Bean | 单例、类型唯一的 Bean |
getBean(String) | 精准按名称查找 | 需手动强转,类型不安全 | 兼容旧代码、名称唯一的场景 |
getBean(String, Class) | 名称 + 类型双重匹配,类型安全 | 需记名称 | 多例、同类型不同名称的 Bean |
System.out.println(userController);
System.out.println(userController2);
System.out.println(userController3);
不同的方式拿到的是同一个对象,单例模式的体现
-
方法注解@Bean注解要配合五大注解使用
package com.example.demo.model;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {private String name;private Integer age;
}
package com.example.demo.component;import com.example.demo.model.UserInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
public class UserInfoComponent {@Beanpublic UserInfo userInfo(){return new UserInfo("Jack",18);}
}
package com.example.demo;import com.example.demo.model.UserInfo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class Demo2Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(Demo2Application.class, args);UserInfo userInfo = context.getBean(UserInfo.class);System.out.println(userInfo);}}
5.2.3 重命名Bean
@Bean(name = "Jack")
public UserInfo userInfo1(){return new UserInfo("Jack",18);
}
@Bean(name = {"Lucy","userInfo2"})
public UserInfo userInfo2(){return new UserInfo("Lucy",19);
}
UserInfo userInfo1 = (UserInfo) context.getBean("Jack");
System.out.println(userInfo1);UserInfo userInfo2 = (UserInfo) context.getBean("userInfo2");
UserInfo userInfo3 = (UserInfo) context.getBean("Lucy");
System.out.println(userInfo2);
System.out.println(userInfo3);
5.3 两类注解对比
5.3.1类注解(@Component
全家桶)
类比:
你开了一家餐厅,类注解就像是给不同岗位的员工发工作牌,告诉顾客:“这个人是干啥的”。
注解 | 作用 | 类比场景 |
@Component | 通用员工牌,标记 “这是餐厅员工” | 杂工(哪里需要去哪里) |
@Controller | 前台接待员,专门负责迎接顾客、处理订单 | 服务员(接单、上菜) |
@Service | 厨师,负责做菜的核心业务 | 厨师(炒菜、炖汤) |
@Repository | 仓库管理员,负责食材的存取 | 库管(管冰箱、进货) |
@Configuration | 餐厅老板,专门配置餐厅的各种设备(如咖啡机、收银机) | 老板(买设备、定规则) |
5.3.2方法注解(@Bean
)
类比: 餐厅需要一些特殊工具(如咖啡机、收银机),但市场上买的都是 “半成品”,需要老板亲自组装。@Bean
就像是老板写的 “组装说明书”。
@Configuration // 餐厅老板
public class RestaurantConfig {@Bean // 组装一台咖啡机public CoffeeMachine coffeeMachine() {CoffeeMachine machine = new CoffeeMachine();machine.setBrand("星巴克"); // 自定义配置machine.setCapacity(100); // 自定义容量return machine;}
}
5.3.3核心区别
维度 | 类注解(如 @Service) | 方法注解(@Bean) |
作用对象 | 员工(类) | 工具(方法返回的对象) |
创建方式 | 餐厅自动招聘(Spring 自动创建实例) | 老板手动组装(自定义初始化逻辑) |
适用场景 | 餐厅内部员工(自己写的类) | 外部买来的工具(第三方类,如 Redis) |
5.3.4协作关系
-
类注解:让 Spring 自动扫描并创建组件(如服务员、厨师)。
-
@Bean
:让 Spring 按你的规则创建特殊工具(如咖啡机、收银机)。
例子: 餐厅老板(@Configuration
)组装好咖啡机(@Bean
),服务员(@Controller
)直接用咖啡机给顾客做咖啡,不用操心咖啡机怎么来的。
5.3.5一句话总结
-
类注解:给员工发工作牌,让 Spring 自动管理员工(类)。
-
@Bean
:写工具组装说明书,让 Spring 按你的规则创建工具(对象)。
5.4 扫描路径
Q:使用前面学习的四个注解声明的bean,一定会生效吗?
A:不一定(原因:bean想要生效,还需要被Spring扫描)
使用五大注解声明的bean,要想生效,还需要配置扫描路径,让Spring扫描到这些注解
也就是通过@ComponentScan来配置扫描路径.
了解:
@ComponentScan({"com.example.demo"})
@SpringBootApplication
public class SpringIocDemoApplication {public static void main(String[] args) {//获取Spring上下⽂对象 ApplicationContext context =SpringApplication.run(SpringIocDemoApplication.class, args);//从Spring上下⽂中获取对象 User u1 = (User) context.getBean("u1");//使⽤对象 System.out.println(u1);}
}
@ComponentScan注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解
@SpringBootApplication中了
默认扫描的范围是SpringBoot启动类所在包及其子包
把启动类放在我们希望扫描的包的路径下,这样我们定义的bean就都可以被扫描到
6.DI 详解
依赖注入是一个过程,是指IoC容器在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象
简单来说就是把对象取出来放到某个类的属性中
关于依赖注入,Spring也给我们提供了三种方式:
-
属性注入(FieldInjection)
-
构造方法注入(ConstructorInjection)
-
Setter注入(SetterInjection)
6.1 属性注入
属性注入是使用@Autowired
实现的,将 Service类注入到Controller类中.
@Controller
public class UserController {@Autowiredprivate UserService userService;public void say(){System.out.println("UserController say...");userService.say();}
}
@Service
public class UserService {public void say(){System.out.println("UserService say...");}
}
@SpringBootApplication
public class Demo2Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(Demo2Application.class, args);UserController userController = context.getBean(UserController.class);userController.say();}}
6.2 构造方法注入
@Controller
public class UserController {private final UserService userService;public UserController(UserService userService) {this.userService = userService;}public void say(){System.out.println("UserController say...");userService.say();}
}
注意事项:如果类只有一个构造方法,那么@Autowired注解可以省略;如果类中有多个构造方法,那么需要添加上@Autowired来明确指定到底使用哪个构造方法。
@Controller
public class UserController {private UserService userService;@Autowiredpublic UserController(UserService userService) {System.out.println("有参构造方法");this.userService = userService;}public UserController() {System.out.println("无参构造方法");}public void say(){System.out.println("UserController say...");userService.say();}
}
6.3 Setter注入
Setter注入和属性的Setter方法实现类似,只不过在设置set方法的时候需要加上@Autowired注解,
如下代码所示:
@Controller
public class UserController {private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void say(){System.out.println("UserController say...");userService.say();}
}
6.4 三种注解优缺点分析
注入方式 | 优点 | 缺点 | 适用场景 / 推荐版本 |
属性注入 | 简洁,使用方便,直接在属性上标注@Autowired等注解即可完成注入 | 1. 仅适用于 IoC 容器,非 IoC 容器环境无法使用; 2. 使用时才可能暴露 NPE(空指针异常); 3. 无法注入被final修饰的属性 | 简单场景快速开发,Spring 无特定版本强推(但因缺点,实际少用) |
构造函数注入 | 1. 可注入final修饰的属性; 2. 注入对象不可被修改,保证稳定性; 3. 依赖在构造阶段执行,对象使用前已完全初始化; 4. 通用性好,基于 JDK 构造方法,适配各类框架 | 注入多个对象时,构造函数参数多,代码繁琐 | 需确保依赖稳定、不可变场景,Spring 4.X 及以上推荐 |
Setter 注入 | 方便在类实例化后,重新配置、注入对象,灵活调整依赖 | 1. 无法注入final修饰的属性; 2. Setter 方法可能被多次调用,注入对象有被修改风险 | 需动态调整依赖场景,Spring 3.X 推荐(现在逐渐被构造注入替代) |
6.5 @Autowired存在的问题
当同⼀类型存在多个bean时,使用@Autowired会存在问题
报错的原因是,非唯⼀的Bean对象。
如何解决上述问题呢?Spring提供了以下几种解决方案:
-
@Primary
-
@Qualifier
-
@Resource
6.5.1 @Primary
使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现
@Component
public class UserInfoComponent {@Beanpublic UserInfo userInfo(){return new UserInfo("Jack",18);}@Beanpublic UserInfo userInfo1(){return new UserInfo("Jack",18);}@Primary//指定该bean为默认bean的实现 @Beanpublic UserInfo userInfo2(){return new UserInfo("Lucy",19);}}
@Component
public class UserComponent {@Autowiredprivate UserInfo ui;public void say(){System.out.println("UserComponent say");System.out.println(ui);}
}
@SpringBootApplication
public class Demo2Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(Demo2Application.class, args);UserComponent userComponent = context.getBean(UserComponent.class);userComponent.say();}}
6.5.2 @Qualifier
使用@Qualifier注解:指定当前要注入的bean对象。在@Qualifier的value属性中,指定注入的bean的名称。
-
@Qualifier注解不能单独使用,必须配合@Autowired使用
@Component
public class UserComponent {@Qualifier("userInfo2")@Autowiredprivate UserInfo ui;public void say(){System.out.println("UserComponent say");System.out.println(ui);}
}
@Component
public class UserComponent {@Qualifier("userInfo3")@Autowiredprivate UserInfo ui;public void say(){System.out.println("UserComponent say");System.out.println(ui);}
}
@Bean
public String name(){return "Luka";
}
//方法一:
@Primary
@Bean
public String name1(){return "Coco";
}
//@Primary
@Bean
public UserInfo userInfo3(String name3){return new UserInfo(name3,22);
}//方法二
@Bean
public String name(){return "Luca";
}
@Bean
public UserInfo userInfo3(@Qualifier("name")String name3){return new UserInfo(name3,22);
}
如果两个注解同时用的话,@Qualifier
优先级更高
6.5.3 @Resource
jdk提供的注解
使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。
@Component
public class UserComponent {@Resource(name = "userInfo3")@Autowiredprivate UserInfo ui;public void say(){System.out.println("UserComponent say");System.out.println(ui);}
}
@Autowired和@Resource的区别
-
@Autowired根据类型匹配(优先按照类型匹配,如果同类型有多个对象,按照名称匹配) @Resource根据名称匹配(前提是类型匹配)
-
@Autowired和@Resource基本原则都是根据类型匹配,但是@Autowired不能指定名称
-
@Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
7.总结
7.1 Spring,Spring Boot和Spring MVC的关系及区别
Spring:简单来说,Spring是一个轻量级,一站式,模块化,其目的是用于简化企业级应用程序开发
Spring的主要功能:管理对象,以及对象之间的依赖关系,面向切面编程,数据库事务管理,数据访
问,web框架支持等.
但是Spring具备高度可开放性,并不强制依赖Spring,开发者可以自由选择Spring的部分或者全
部,Spring可以无缝继承第三方框架,比如数据访问框架(Hibernate、JPA),web框架(如Struts、
JSF)
SpringMVC:SpringMVC是Spring的一个子框架,Spring诞生之后,大家觉得很好用,于是按照MVC
模式设计了一个MVC框架(一些用Spring解耦的组件),主要用于开发WEB应用和网络接口,所以,
SpringMVC 是一个Web框架.
SpringMVC基于Spring进行开发的,天生的与Spring框架集成.可以让我们更简洁的进行Web层
开发,支持灵活的URL到页面控制器的映射,提供了强大的约定大于配置的契约式编程支持,非常
容易与其他视图框架集成,如Velocity、FreeMarker等
SpringBoot:SpringBoot是对Spring的一个封装,为了简化Spring应用的开发而出现的,中小型
企业,没有成本研究自己的框架,使用SpringBoot可以更加快速的搭建框架,降低开发成本,让开发
人员更加专注于Spring应用的开发,而无需过多关注XML的配置和一些底层的实现。
SpringBoot是个脚手架,插拔式搭建项目,可以快速的集成其他框架进来.
比如想使用SpringBoot开发Web项目,只需要引入SpringMVC框架即可,Web开发的工作是
SpringMVC完成的,而不是SpringBoot,想完成数据访问,只需要引入Mybatis框架即可.
SpringBoot只是辅助简化项目开发的,让开发变得更加简单,甚至不需要额外的web服务器,直接
生成jar包执行即可.
最后一句话总结:Spring MVC和Spring Boot都属于Spring,SpringMVC 是基于Spring的一个
MVC框架,而SpringBoot是基于Spring的一套快速开发整合包。
7.2 Bean的命名
-
五大注解存储的bean
①前两位字母均为大写,bean名称为类名
②其他的为类名首字母小写
③通过value属性设置@Controller(value="user")
-
@Bean注解存储的bean
①bean名称为方法名
②通过name属性设置(@Bean(name= {"u1","user1"})
7.3 常见面试题
-
三种注入方式的优缺点
-
常见注解有哪些?分别是什么作用?
web url映射: @RequestMapping
参数接收和接口响应:@RequestParam,@RequestBody,@ResponseBody
bean的存储: @Controller, @Service, @Repository, @Component,@Configuration,@Bean
bean的获取: @Autowired, @Qualifier, @Resource -
@Autowired 和@Resource 区别
-
说下你对Spring, SpringMVC, Springboot的理解