一.什么是Spring
我们知道Spring是一个生态,里面包含众多的工具,可以在我们进行Java项目开发中,帮助我们完成一些功能,给我们带来一些便利。
总的一句话来说:Spring其实就是一个包含众多工具的IoC容器。
二.什么是容器
可以盛放东西的物品就是容器。
例如:
list/map 是装数据的容器
tomcat是装web的容器
既然是容器就要管理这些存放的东西,也就是容器内存放的这些东西的存和去。

Spring是一个管理对象的容器。
三.什么是IoC
IoC(控制反转,Inversion of Control)是一种编程思想。
所谓控制反转,实质上是指控制权的转移:
举个例子,自动驾驶技术便是一种控制反转的体现。在传统的汽车驾驶中,驾驶控制权掌握在驾驶员手中,而在自动驾驶模式下,控制权则交由车辆的自动化系统。这种控制权的转移便是控制反转的体现------本来由司机掌控的驾驶权,现在转交给了车辆系统。

四.Spring其实就是一个包含众多工具的IoC容器
Spring其实就是一个包含众多工具的IoC容器。
也就是说Spring是一个包含众多工具的一个实现了控制反转思想的管理对象的容器。
我们知道当在类中需要使用某一个类型的对象的时候,我们直接new一个就好了:


但是现在不用了,我们直接找Spring要就可以。 在类上⾯添加 @RestController 和 @Controller 注解, 就是把这个类交给Spring管理, Spring 框架启动时就会加载该类. 将这个类的对象交给Spring管理, 这就是IoC思想,在Spring中的体现。
五.传统的程序开发
在传统的程序开发模式中,对于一个汽车对象我们的设计思路是:
先设计轮子(Tire),然后根据轮子的大小设计地盘(Bottom),接着根据地盘设计车身(Framework),最后根据车身设计好整个汽车(Car)。

代码实现如下:
java
public class NewCarExample {
public static void main(String[] args) {
Car car = new Car();
car.run();
}
/**
* 汽⻋对象
*/
static class Car {
private Framework framework;
public Car() {
framework = new Framework();
System.out.println("Car init....");
}
public void run(){
System.out.println("Car run...");
}
}
/**
* ⻋⾝类
*/
static class Framework {
private Bottom bottom;
public Framework() {
bottom = new Bottom();
System.out.println("Framework init...");
}
}
/**
* 底盘类
*/
static class Bottom {
private Tire tire;
public Bottom() {
this.tire = new Tire();
System.out.println("Bottom init...");
}
}
/**
* 轮胎类
*/
static class Tire {
// 尺⼨
private int size;
public Tire(){
this.size = 17;
System.out.println("轮胎尺⼨:" + size);
}
}
}
这样的设计看起来没有问题,但是可维护性却很低:
此时如果对轮子进行更改,那么地盘车身汽车的整体都要随着轮子的改变发生改变。这显然是非常反人类的设计。



完整代码如下:
java
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);
}
}
}
从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调用链上的所有代码都需要跟着进行更改,这样的程序的耦合度非常高(修改一处diamond,影响其他处的代码进行修改)。
六.解决方案
在上面的程序中,我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改。同样因为我们是根据地盘设计的车身,那么车身也得改,同理汽车的设计也得修改,也就是因为车轮的更改,整个汽车的设计都跟着修改了一遍。

此时我们不妨换一种思路,我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计地盘,根据地盘来设计轮子的尺寸。
这时候,依赖关系就倒置过来了:轮子依赖地盘,地盘依赖车身,车身依赖汽车。
这就类似我们打造一辆完整的汽车,如果所有的配件都是自己造的,那么当客户需求发生改变的时候,比如轮胎的尺寸不再是原来的尺寸,那我们就要自己动手来改,如果我们是把轮胎外包出去,那么即使轮胎的尺寸发生改变了,我们只需要向代理工厂下订单就行了,我们自身是不需要出力的。
如何来实现呢:
我们可以尝试不在每个类中自己创建下级类,如果自己创建下级列就会出现当下级类发生改变操作,自己也要跟着修改。
此时,我们只需要将原来由自己创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修改任何代码,这样就完成了程序的解耦。
七.IoC程序
基于以上思路,我们把调用汽车的程序实例改造一下,把创建子类的方式,改为注入传递的方式。
具体代码实现如下:
java
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的优势
在传统的代码中对象的创建顺序是:Car → Framework → Bottom → Tire
改进之后解耦的代码的对象创建顺序是:Tire → Bottom → Framework → Car
我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,而改进之后的控制权发生的反转,不再是使用⽅对象创建并控制依赖对象了,而是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了。这样的话, 即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
这部分代码, 就是IoC容器做的⼯作。
从上⾯也可以看出来,IoC容器具备以下优点:
资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。第⼀,资源集 中管理,实现资源的可配置和易管理。第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。
资源集中管理: IoC容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从IoC容器中去取 就可以了
我们在创建实例的时候不需要了解其中的细节, 降低了使⽤资源双⽅的依赖程度, 也就是耦合度。Spring 就是⼀种IoC容器, 帮助我们来做了这些资源管理。
九.什么是DI
IoC是一种思想,DI是一种实现方式(Spring实现IoC思想的方式)。
DI:依赖注入,将所需要的资源,注入到等待使用的方法中
IoC 是⼀种思想,也是"⽬标", 而思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就属于具体的实现。所以也可以说, DI 是IoC的⼀种实现。
比如说我今天心情比较好,吃⼀顿好的犒劳犒劳⾃⼰,那么"吃⼀顿好的"是思想和目标(是
IoC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是 DI。
十.IoC & DI 使用
既然Spring是一个IoC容器,那么作为容器,那么它就具备两个最基础的功能:
存和取
Spring容器管理的主要是对象,这些对象,我们称之为"Bean"。我们把这些对象交给Spring管理,由Spring来负责对象的创建和销毁。我们程序只需要告诉Spring,那些需要存,以及如何从Spring中取出对象。

十一.IoC容器(存)
前⾯我们提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。
也就是bean的存储。
对于一个类我们想让Spring帮我们管理这个类的对象需要给这个类打注释:
共有两类注释类型可以实现:
类注解:@Controller、@Service、@Reponsitory、@Component、@Configuration
方法注解:@Bean
其中类注解又称五大注解。
1.@Controller
通过加@Controller注解的方式告诉Spring容器来帮我们管理这个对象。
java
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
public void doController(){
System.out.println("doController....");
}
}

在启动类中获取这个被Spring容器管理的Bean:
java
@SpringBootApplication
public class IoCDiApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(IoCDiApplication.class, args);
UserController userController = applicationContext.getBean(UserController.class);
userController.doController();
}
}




@SpringBootApplication :


默认的@SpringBootApplication中的@ComponentScan是会去找启动方法所在的包中的类及其子包中的类:

2.@Service
java
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void doService(){
System.out.println("doService.....");
}
}

java
UserService userService = applicationContext.getBean(UserService.class);
userService.doService();

通过名称获取Bean:
上面的获取Spring容器中的Bean的方式是通过Bean的类型来获取,但是如果在 Spring容器中同一类型,存在多个Bean,此时这种方法就行不通了。
观察获取Bean的方式:


通过上面的观察,我们发现还可以通过名称的方式来获取Bean:


普通类型:
java
//根据名称来获取Bean
UserService userService2 = (UserService) applicationContext.getBean("userService");
userService2.doService();

两个大写字母开头的类型:
java
@Controller
public class UController {
public void doController(){
System.out.println("doUController....");
}
}

java
UController uController = (UController) applicationContext.getBean("UController");
uController.doController();

通过上面不同方式获取的Bean都是相同的,是同一个对象。
ApplicationContext VS BeanFactory:
从继承关系和功能方面来说:Spring容器有两个顶级的接口:BeanFactory和ApplicationContext。其中BeanFactory提供了基础的访问容器的能力,而ApplicationContext属于BeanFactory的子类,它除了继承了BeanFactory的所有功能之外,它还拥有独特的特性,还添加了对国际化的支持、资源访问支持、以及事件传播等方面的支持。
从性能方面来说:ApplictionContext是一次性加载并初始化所有Bean对象,而BeanFactory是需要哪个才去加载哪个,因此更加轻量。(空间换时间)
3.@Repository



4.@Component



5.Configuration



6.为什么需要这么多注解
让程序员在看到相应的注解后就知道这个部分功能是干什么的:
@Controller:控制层,接收请求,对请求进行处理,并进行响应。
@Service:业务逻辑层,处理具体的业务逻辑。
@Repository :数据访问层,也称为持久层,负责数据访问操作。
@Configuration:配置层,处理项目中的一些配置信息。

通过观察@Controller/@Service/@Repository/@Configuration,发现这些注释中都包含了@Component ,也就说明这些注释均是@Component的衍生类。
IoC的五大注解功能是类似的,但是也不尽相同,例如Controller还被赋予了其他功能,如果想被外界获取只能使用@Controller注释,也就是通过HTTP请求获取。
后端在返回数据的时候尽量避免返回中文。
7.@Bean
从上面我们发现使用五大注解来管理对象,不论什么时候怎么样取,相同类型下,取出的都是同一对象。
而且对于五大注解来说,在使用的时候只能在我们自己的代码中使用,如果我们让Spring帮我们管理外部包中的类,五大注解是办不到的。
所以在上面两种情况下,我们就需要使用@Bean。
我们试着写一些@Bean的方法:
首先先定义一个对象:
java
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
编写@Bean注释的方法:
@Bean表示这个方法返回的是一个Bean,Spring容器会托管它;
方法名user()对应的Bean的名字就是name;
方法的返回值是一个User对象,会被注册为一个类型为User的Bean;
此时Spring容器中就相当于有一个user对象;
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
public class BeanConfig {
@Bean
public User user (){
User user = new User();
user.setName("张三");
user.setAge(30);
return user;
}
}
在启动类中获取User对象:
java
@SpringBootApplication
public class IoCDiApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(IoCDiApplication.class, args);
User user = (User) applicationContext.getBean("user");
System.out.println("user = " + user);
}
}
启动后发现Spring容器找不到这个对象:

出现这种情况的原因是,在Spring框架的设计中,方法注解@Bean要配合类注解才能将对象正常的存储到Spring容器中:
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public User user (){
User user = new User();
user.setName("张三");
user.setAge(30);
return user;
}
}

此时还有一个问题:
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public User user (){
User user = new User();
user.setName("张三");
user.setAge(30);
return user;
}
@Bean
public User userOne (){
User user = new User();
user.setName("李四");
user.setAge(30);
return user;
}
}
java
@SpringBootApplication
public class IoCDiApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(IoCDiApplication.class, args);
User user = (User) applicationContext.getBean(User.class);
System.out.println("user = " + user);
}
}

如果有多个对象的时候使用对象的类型来获取对象时,Spring就不知道我们到底想要获取那个了,所以此时应该使用Bean的名称来获取,使用@Bean注解时Bean的名称是方法名,或者使用类型加名称的方式也可以获取。
java
@SpringBootApplication
public class IoCDiApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(IoCDiApplication.class, args);
User user = (User) applicationContext.getBean("user");
System.out.println("user = " + user);
}
}

如何进行参数传递:
参数 String name
会自动注入 Spring 容器中名为 name
的 Bean(就是上面那个字符串 "张三"
);这是 Spring 的一种 方法参数注入方式 (基于方法参数类型匹配或名称匹配);方法内部创建了一个 User
实例,设置了名字(来自 name Bean)和年龄 30;最终返回并注册这个 User
Bean 到 Spring 容器中。
java
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "张三";
}
@Bean
public User user (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
}
@Bean重命名
可以通过设置name属性给Bean对象进行重命名操作,代码如下:
java
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "张三";
}
@Bean(name = {"u1","user1"})
public User user (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
}
java
@SpringBootApplication
public class IoCDiApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(IoCDiApplication.class, args);
User user = (User) applicationContext.getBean("user1");
System.out.println("user = " + user);
}
}
其中name是可以省去的:
java
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "张三";
}
@Bean({"u1","user1"})
public User user (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
}
如果名称只有一个{}也可以省去:
java
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "张三";
}
@Bean("u1")
public User user (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
}
十二.DI(取)依赖注入
三种方式:
1.属性注入
@Autowired
属性注入以类型进行匹配,与注入的属性名称无关,但是如果一个类型存在多个对象时,优先名称匹配,如果名称都匹配不上,就会报错。
属性注入无法注入Final修饰的属性,因为Fianl是定义时赋值或者构造方法中进行赋值。
java
import org.springframework.stereotype.Component;
@Component
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
java
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private User user;
public String doService(){
user.setName("张三");
user.setAge(30);
return user.toString();
}
}
java
import org.example.ioc_di.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/UserController")
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}

2.构造方法注入
它通过构造方法将所需的依赖项传递给类的属性。
java
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
public UserController(){}
@Autowired
public UserController(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}
注意:当类中只有一个构造方法时,@Autowired
可以省略;但当类中有多个构造方法时,必须使用 @Autowired
来明确指定 Spring 使用哪个构造方法进行依赖注入。如果没有明确指定,Spring 将抛出异常。
3. Setter注入(方法注入)
java
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}

4.三种注入方式的优点和缺点
属性注入(Field Injection)
优点:
简洁,使用方便
缺点:
只能用于 IoC 容器中,如果是非 IoC 容器不可用
并且只有在使用时才会出现空指针异常(NPE)
不能注入一个 final
修饰的属性
构造函数注入(Constructor Injection,Spring 4.x 推荐)
优点:
可以注入 final
修饰的属性
注入的对象不会被修改
依赖对象在使用前一定会被完全初始化(构造方法在类加载阶段执行)
通用性好,构造方法是 JDK 支持的,换框架也通用
缺点:
注入多个对象时,代码会比较繁琐
Setter 注入(Spring 3.x 推荐)
优点:
方便在类实例化之后,重新对该对象进行配置或注入
缺点:
不能注入 final
修饰的属性
注入对象可能会被改动,因为 setter
方法可能会被多次调用,存在被修改的风险
十三.@Autowired存在的问题
存在的问题:
java
package org.example.ioc_di.controller;
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "李四";
}
@Bean("u1")
public User userOne (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
@Bean
public User userTwo (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
}
java
package org.example.ioc_di.service;
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private User user;
public String doService(){
user.setName("张三");
user.setAge(30);
return user.toString();
}
}
java
package org.example.ioc_di.controller;
import org.example.ioc_di.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}
此时运行代码会报错:


因为此时同一个类型的bean在我们的项目中有多个,我们交给Spring托管,但是当我们和Spring要Bean的时候,Spring蒙了它并不知道此时到底给我们那个,所以此时就需要我们指定Spring给我们那个。
四种解决方法:
1.属性名和需要使用的对象名保持一致:
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "李四";
}
@Bean("u1")
public User userOne (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
@Bean
public User userTwo (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
}
java
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private User userTwo;
public String doService(){
userTwo.setName("张三");
userTwo.setAge(30);
return userTwo.toString();
}
}

java
import org.example.ioc_di.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}

2.使用@Primary注解标识默认的对象
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "李四";
}
@Primary
@Bean("u1")
public User userOne (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
@Bean
public User userTwo (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
}
java
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private User user;
public String doService(){
user.setName("张三");
user.setAge(30);
return user.toString();
}
}
java
import org.example.ioc_di.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}
3.使用@Qualifier注解:指定当前要注入的bean对象。在@Qualifier的value属性中,指定注入的bean的名称。
@Qualifier注解不能单独使用,必须配合@Autowired使用。
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "李四";
}
@Primary
@Bean("u1")
public User userOne (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
@Bean
public User userTwo (String name){
User user = new User();
user.setName("wuhu");
user.setAge(30);
return user;
}
}
java
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
@Qualifier("userTwo")
private User user;
public String doService(){
//user.setName("张三");
user.setAge(30);
return user.toString();
}
}
java
import org.example.ioc_di.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}
4.使用@Resource注解
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "李四";
}
@Primary
@Bean("u1")
public User userOne (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
@Bean
public User userTwo (String name){
User user = new User();
user.setName("wuhu");
user.setAge(30);
return user;
}
}
java
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
@Resource(name = "userTwo")
private User user;
public String doService(){
//user.setName("张三");
user.setAge(30);
return user.toString();
}
}
java
import org.example.ioc_di.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}
还有一种情况就是,如果存在方法重载的情况,此时Spring给我们Bean是随机的:
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "李四";
}
//@Primary
//@Bean("u1")
@Bean
public User userOne (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
@Bean
public User userOne (){
User user = new User();
user.setName("wuhu");
user.setAge(30);
return user;
}
}
java
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
//@Resource(name = "userTwo")
@Autowired
private User user;
public String doService(){
//user.setName("张三");
user.setAge(30);
return user.toString();
}
}
java
import org.example.ioc_di.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@RequestMapping("/UserController")
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
@RequestMapping("/doController")
@ResponseBody
public String doController(){
return userService.doService();
}
}
此时这种情况可以通过给Bean重命名的方法解决。
java
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class BeanConfig {
@Bean
public String name(){
return "李四";
}
//@Primary
@Bean("u1")
//@Bean
public User userOne (String name){
User user = new User();
user.setName(name);
user.setAge(30);
return user;
}
@Bean
public User userOne (){
User user = new User();
user.setName("wuhu");
user.setAge(30);
return user;
}
}
java
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
@Resource(name = "userOne")
private User user;
public String doService(){
//user.setName("张三");
user.setAge(30);
return user.toString();
}
}
@Autowired和 @Resource的区别
@Autowired是Spring框架提供的注释,而@Resource是JDK提供注释
@Autowired默认是按照类型注入,而@Resource是按照名称注入。相比于@Autowired来说,@Resource支持更多的参数设置,例如name设置,根据名称获取Bean。