Spring-IoCDI
一.什么是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)。
代码实现如下:
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);}}
}
这样的设计看起来没有问题,但是可维护性却很低:
此时如果对轮子进行更改,那么地盘车身汽车的整体都要随着轮子的改变发生改变。这显然是非常反人类的设计。
完整代码如下:
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程序
基于以上思路,我们把调用汽车的程序实例改造一下,把创建子类的方式,改为注入传递的方式。
具体代码实现如下:
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
九.什么是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容器来帮我们管理这个对象。
import org.springframework.stereotype.Controller;@Controller
public class UserController {public void doController(){System.out.println("doController....");}
}
在启动类中获取这个被Spring容器管理的Bean:
@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
import org.springframework.stereotype.Service;@Service
public class UserService {public void doService(){System.out.println("doService.....");}
}
UserService userService = applicationContext.getBean(UserService.class);userService.doService();
通过名称获取Bean:
上面的获取Spring容器中的Bean的方式是通过Bean的类型来获取,但是如果在 Spring容器中同一类型,存在多个Bean,此时这种方法就行不通了。
观察获取Bean的方式:
通过上面的观察,我们发现还可以通过名称的方式来获取Bean:
普通类型:
//根据名称来获取Bean
UserService userService2 = (UserService) applicationContext.getBean("userService");userService2.doService();
两个大写字母开头的类型:
@Controller
public class UController {public void doController(){System.out.println("doUController....");}
}
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的方法:
首先先定义一个对象:
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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
编写@Bean注释的方法:
@Bean表示这个方法返回的是一个Bean,Spring容器会托管它;
方法名user()对应的Bean的名字就是name;
方法的返回值是一个User对象,会被注册为一个类型为User的Bean;
此时Spring容器中就相当于有一个user对象;
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;public class BeanConfig {@Beanpublic User user (){User user = new User();user.setName("张三");user.setAge(30);return user;}
}
在启动类中获取User对象:
@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容器中:
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class BeanConfig {@Beanpublic User user (){User user = new User();user.setName("张三");user.setAge(30);return user;}
}
此时还有一个问题:
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class BeanConfig {@Beanpublic User user (){User user = new User();user.setName("张三");user.setAge(30);return user;}@Beanpublic User userOne (){User user = new User();user.setName("李四");user.setAge(30);return user;}
}
@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的名称是方法名,或者使用类型加名称的方式也可以获取。
@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 容器中。
@Configuration
public class BeanConfig {@Beanpublic String name(){return "张三";}@Beanpublic User user (String name){User user = new User();user.setName(name);user.setAge(30);return user;}
}
@Bean重命名
可以通过设置name属性给Bean对象进行重命名操作,代码如下:
@Configuration
public class BeanConfig {@Beanpublic String name(){return "张三";}@Bean(name = {"u1","user1"})public User user (String name){User user = new User();user.setName(name);user.setAge(30);return user;}
}
@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是可以省去的:
@Configuration
public class BeanConfig {@Beanpublic String name(){return "张三";}@Bean({"u1","user1"})public User user (String name){User user = new User();user.setName(name);user.setAge(30);return user;}
}
如果名称只有一个{}也可以省去:
@Configuration
public class BeanConfig {@Beanpublic 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是定义时赋值或者构造方法中进行赋值。
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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate User user;public String doService(){user.setName("张三");user.setAge(30);return user.toString();}
}
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 {@Autowiredprivate UserService userService;@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
2.构造方法注入
它通过构造方法将所需的依赖项传递给类的属性。
@RequestMapping("/UserController")
@Controller
public class UserController {private UserService userService;public UserController(){}@Autowiredpublic UserController(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
注意:当类中只有一个构造方法时,@Autowired
可以省略;但当类中有多个构造方法时,必须使用 @Autowired
来明确指定 Spring 使用哪个构造方法进行依赖注入。如果没有明确指定,Spring 将抛出异常。
3. Setter注入(方法注入)
@RequestMapping("/UserController")
@Controller
public class UserController {private UserService userService;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic 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存在的问题
存在的问题:
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 {@Beanpublic String name(){return "李四";}@Bean("u1")public User userOne (String name){User user = new User();user.setName(name);user.setAge(30);return user;}@Beanpublic User userTwo (String name){User user = new User();user.setName(name);user.setAge(30);return user;}
}
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 {@Autowiredprivate User user;public String doService(){user.setName("张三");user.setAge(30);return user.toString();}
}
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;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
此时运行代码会报错:
因为此时同一个类型的bean在我们的项目中有多个,我们交给Spring托管,但是当我们和Spring要Bean的时候,Spring蒙了它并不知道此时到底给我们那个,所以此时就需要我们指定Spring给我们那个。
四种解决方法:
1.属性名和需要使用的对象名保持一致:
import org.example.ioc_di.model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class BeanConfig {@Beanpublic String name(){return "李四";}@Bean("u1")public User userOne (String name){User user = new User();user.setName(name);user.setAge(30);return user;}@Beanpublic User userTwo (String name){User user = new User();user.setName(name);user.setAge(30);return user;}
}
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate User userTwo;public String doService(){userTwo.setName("张三");userTwo.setAge(30);return userTwo.toString();}
}
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;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
2.使用@Primary注解标识默认的对象
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 {@Beanpublic String name(){return "李四";}@Primary@Bean("u1")public User userOne (String name){User user = new User();user.setName(name);user.setAge(30);return user;}@Beanpublic User userTwo (String name){User user = new User();user.setName(name);user.setAge(30);return user;}
}
import org.example.ioc_di.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate User user;public String doService(){user.setName("张三");user.setAge(30);return user.toString();}
}
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;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
3.使用@Qualifier注解:指定当前要注入的bean对象。在@Qualifier的value属性中,指定注入的bean的名称。
@Qualifier注解不能单独使用,必须配合@Autowired使用。
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 {@Beanpublic String name(){return "李四";}@Primary@Bean("u1")public User userOne (String name){User user = new User();user.setName(name);user.setAge(30);return user;}@Beanpublic User userTwo (String name){User user = new User();user.setName("wuhu");user.setAge(30);return user;}
}
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();}
}
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;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
4.使用@Resource注解
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 {@Beanpublic String name(){return "李四";}@Primary@Bean("u1")public User userOne (String name){User user = new User();user.setName(name);user.setAge(30);return user;}@Beanpublic User userTwo (String name){User user = new User();user.setName("wuhu");user.setAge(30);return user;}
}
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();}
}
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;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
还有一种情况就是,如果存在方法重载的情况,此时Spring给我们Bean是随机的:
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 {@Beanpublic String name(){return "李四";}//@Primary//@Bean("u1")@Beanpublic User userOne (String name){User user = new User();user.setName(name);user.setAge(30);return user;}@Beanpublic User userOne (){User user = new User();user.setName("wuhu");user.setAge(30);return user;}
}
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")@Autowiredprivate User user;public String doService(){//user.setName("张三");user.setAge(30);return user.toString();}
}
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;@Autowiredpublic void setUserService(UserService userService){this.userService = userService;}@RequestMapping("/doController")@ResponseBodypublic String doController(){return userService.doService();}
}
此时这种情况可以通过给Bean重命名的方法解决。
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 {@Beanpublic String name(){return "李四";}//@Primary@Bean("u1")//@Beanpublic User userOne (String name){User user = new User();user.setName(name);user.setAge(30);return user;}@Beanpublic User userOne (){User user = new User();user.setName("wuhu");user.setAge(30);return user;}
}
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。