当前位置: 首页 > news >正文

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

        我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 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容器来帮我们管理这个对象。

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。        

http://www.lryc.cn/news/597818.html

相关文章:

  • QT的moveToThread 用法
  • 使用Qt下QAudioOutput播放声音
  • Qt 常用控件 - 1
  • iview表单验证一直提示为空的几个原因?
  • DDD领域驱动设计C++实现案例:订单管理系统
  • 【读代码】Facebook Denoiser:开源端到端语音降噪系统原理与实战
  • 2025 ACT 汽车功能安全相关PPT分享
  • Linux网络:网络层-IP协议
  • 飞算JavaAI:从“工具革命”到“认知革命”——开发者如何借力AI重构技术竞争力
  • 【已解决】Jetson Orin NX apt更换国内源
  • ​​SBOM 软件供应链安全(转)
  • Class14参数管理
  • 从零搭建 OpenCV 项目(新手向)-- 第二天 OpenCV图像预处理(一)
  • lammps滚动模拟
  • AJAX案例合集
  • LeetCode热题100--383
  • MCU芯片AS32S601在卫星光纤放大器(EDFA)中的应用探索
  • Github上传文件流程图
  • mysql中ROW_NUMBER()、RANK()、DENSE_RANK()用法及区别
  • SpringBoot整合Langchain4j
  • ZKmall开源商城微服务架构实战:Java 商城系统的模块化拆分与通信之道
  • 开源的语音合成大模型-Cosyvoice使用介绍
  • 【Linux庖丁解牛】— 信号量 !
  • Petalinux的常用指令
  • python3写一个异步流式 http 接口服务调用大模型(async, stream, sanic)---6.2
  • 若依前后端分离版学习笔记(二)——系统菜单介绍
  • 前端资源缓存优化案例:深入探讨 Nginx 配置中的 Cache-Control 头部叠加问题
  • 【科研绘图系列】R语言绘制黑白填充等显著性标记条形图
  • Java按模板导出Excel
  • Redis能完全保证数据不丢失吗?