SpringIoC&DI

  前言👀~

上一章我们介绍了Spring MVC,今天介绍Spring核心功能之一IoC

Spring到底是什么?

Spring IoC

什么是 IoC 容器?

IoC 介绍

DI 介绍

IoC详解

获取Bean对象的其他方式

Bean的存储

方法注解 @Bean

扫描路径

DI详解

1. 属性注入

2. 构造方法注入

3. Setter 注入

@Autowired存在的问题


如果各位对文章的内容感兴趣的话,请点点小赞,关注一手不迷路,讲解的内容我会搭配我的理解用我自己的话去解释如果有什么问题的话,欢迎各位评论纠正 🤞🤞🤞

47497722484f4d519a7e014f8100ec05.png

个人主页:N_0050-CSDN博客

相关专栏:java SE_N_0050的博客-CSDN博客  java数据结构_N_0050的博客-CSDN博客  java EE_N_0050的博客-CSDN博客


Spring到底是什么?

Spring 是包含了众多⼯具⽅法的 IoC 容器,Spring两个核心思想,IoC和AOP!!!

Spring IoC

什么是容器?

容器是⽤来容纳某种物品的(基本)装置,前面数据结构学的List、Map等属于装数据的容器,帮我们管理数据,还有tomcat,它属于装web的容器可以部署很多个项目并且帮我们管理项目反正就是能存东西我们就可以简单的认为是一个容器,而我们的Spring容器装的是对象,它来帮我们管理对象。对象这个词,在Spring的范围内,称为为bean

什么是 IoC 容器?

IoC 是Spring的核⼼思想,注意这是一个思想!!!IoC (控制反转)是啥?控制权反转就是将创建对象的控制权,交给了Spring。也就是说Spring是一个"控制反转"的容器。类似⾃动驾驶,车辆的控制权交给了驾驶⾃动化系统来控制

    •    控制权:之前创建对象的控制权是由java里面的一些程序控制的,也就是其他对象去创建的,就是使用者去创建的,谁用谁创建例如图中bookService是由BookController类创建的


    •    反转:现在使用BookService对象,不用BookController去创建了由Spring去创建这就是IoC的思想例如图中的BookService加了@Service注解,看到后面就知道为什么了

以上所述就是IoC的意思,可能比较抽象既然都称为容器了,Spring容器自然也就了创建对象、从对象中取数据的功能,这是Spring在IoC 这块具备的功能Spring是一个IoC 容器,控制反转的容器,还是上面说的创建对象的控制权,交给了Spring,由Spring创建管理对象


其实IoC在前⾯就已经体现已经使⽤了我们在前⾯讲到在类上⾯添加 @RestController 和@Controller 注解,就是把这个对象交给Spring管理Spring 框架启动时就会加载该类把对象交给Spring管理, 就是IoC思想。所以这些注解是控制反转的应用了


小结:IoC控制反转,就是将对象的控制权交给Spring的IoC容器,由IoC容器创建及管理对象


IoC 介绍

IoC主要目的就是解耦对于耦合性高的代码,我们使用IoC的思想去解耦当我们使用IoC的思想的时候,先把对象创建好,然后要使用的时候直接拿即可这些对象交给IoC容器进行管理就好比苹果,通过富士康工厂生产的零件去拿过来然后组成一个个电子产品

刚才上面的控制权知识点提到bookService是由BookController类创建的,这种写法如果我们要使用这个属性每次都要创建这个对象,他们之间的耦合性高,因为我们要使用bookService需要依赖BookController类

我们换一种方式,只需要将原来由⾃⼰创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也⽆需修改任何代码,这样就完成了程序的解耦

IoC容器具备以下优点:

1. 资源集中管理:IoC容器会帮我们管理⼀些资源(对象等)我们需要使⽤时只需要从IoC容器中去取就可以了

2. 我们在创建实例的时候不需要了解其中的细节降低了使用资源双方的依赖程度,也就是耦合度


DI 介绍

上面说了IoC是一种思想,但是如何实现呢?DI(依赖注⼊) DI 是IoC的⼀种实现方式两者结合就是我需要啥,我就去实现它比如我想要吃汉堡,走去KFC吃去,就去实现

什么是依赖注入?

容器在运⾏期间, 动态的为应用程序提供运⾏时所依赖的资源,称之为依赖注⼊

 现在我们去实现,我们通过@Autowired注解告诉Spring,从容器中取出这个对象,赋值给当前对象的属性

这两个代码一个意思,下面这个代码相当于实例化了BookController,也实例化了bookService

@Component注解

    •    但是呢要取之前得需要存啊还没把这个对象存入容器中如何存呢?我们通过@Component注解修饰类告诉Spring帮我们存这个对象,不只这个注解可以,下面就有解释

@RestController和@Controller

    •    我们会发现@RestController注解中的@Controller注解中有@Componet注解所以@Controller注解和@Componet注解都是告诉Spring存储对象的一种方式


IoC详解

IoC主要就是Bean的存储我们需要告诉Spring哪些对象是需要它帮我们创建的如何告诉Spring呢?一种方式是类注解,一种是方法注解

获取Bean对象的其他方式

如何观察这个对象已经存在Spring容器当中了呢?如何从Spring容器中获取对象呢?

    •    因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下⽂

    •    ApplicationContext:Spring上下文,返回的就是Spring运行环境。这个上下⽂,就是指当前的运行环境,也可以看作是⼀个容器,容器⾥存了很多内容,这些内容是当前运⾏的环境。注意选这个ApplicationContext选的是接口

在启动类中,我们去获取

输出结果,说明我们获取到Bean了

getBean方法的参数解释:

图中的名称什么意思呢?就是Spring在帮我管理对象的时候会给每个对象起一个名字,并且这个名称是唯一的。类似给学生分配学号一样
 
注意:特殊情况,如果类名前两位字母都为大写 ,Bean的名称则为类名


注意:点进源码里会发现获取bean对象, 是⽗类BeanFactory提供的功能


ApplicationContext 和 BeanFactory的区别:

Spring 容器有两个顶级的接口ApplicationContext 和BeanFactory

    •    继承关系来说:首先ApplicationContext 是BeanFactory的子类所以父类有的子类都有,BeanFactory有的ApplicationContext也都有。BeanFactory 提供了基础的访问容器的能⼒,而ApplicationContext 属于 BeanFactory 的⼦类它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持。还可以拿到一些环境相关的配置


    •    性能方面来说:ApplicationContext 是⼀次性加载并初始化所有的 Bean 对象,所以ApplicationContext 可以称为预加载,而BeanFactory 是需要那个才去加载那个,因此更加轻量 (空间换时间),所以BeanFactory 可以称为懒加载


Bean的存储

把某个对象交给IOC容器管理,需要在类上添加⼀个注解: @Component,⽽Spring框架为了更好的服务web应用程序,提供了更丰富的注解。以下都可以通过在启动类下进行获取然后输出

@Controller(控制器存储)

对应表现层

        UserController userController = context.getBean(UserController.class);
        //使⽤对象
        userController.doController();

@Service(服务存储)

对应业务逻辑层

        UserService userService = context.getBean(UserService.class);
        userService.doService();

根据名称获取Bean,注意是小驼峰的命名! 并且要强转

        //根据名称获取Bean 注意是小驼峰的命名! 并且要强转
        UserService userService1 = (UserService) context.getBean("userService");
        userService1.doService();

@Repository(仓库存储)

对应数据层/持久层

        UserRepository repository = context.getBean(UserRepository.class);
        repository.doRepository();

@Component(组件存储)

        UserComponent component = context.getBean(UserComponent.class);
        component.doComponent();


@Configuration(配置存储)

配置层,处理项⽬中的⼀些配置信息

        UserConfig userConfig = context.getBean(UserConfig.class);
        userConfig.doUserConfig();


小结:以上注解都是告诉Spring帮我们存储对象(Bean)到容器中


为什么要这么多类注解?

这个和前面讲的应用分层是呼应的程序员看到类注解之后,就能直接了解当前类的⽤途根据类的用途选择合适的注解标注,在开发中会更加规范

程序的应用分层,调用流程如下

类注解之间的关系

这几个类注解点进源码看会发现这些类都带有@Component注解这些注解被称为 @Component 的衍生注解

什么意思呢?就是根据@Component 来变化成其他的类,可以认为是父子关系,其实没有什么区别只是词的区别

但是注意@Controller注解还被赋予一个额外的功能,如果想被外界访问,只能使用@Controller注解。虽然看起来都一样,但这只是表面,只是定义了一个注解而已。注解的真正实现不在这,在Spring源码中Spring对注解赋予了一些其他的功能


方法注解 @Bean

上述讲解的五大注解只能加在类上并且只能加在自己的代码上

    •    如果引入一个第三方Jar包,使用里面的类,也希望Spring进行管理的话,是没办法加五大注解,但可以使用@Bean注解


    •    还有一种场景,对于一个类,定义多个对象时,比如数据库操作,定义多个数据源(也就需要多个对象)

我们使用五大注解时,不管从Spring容器中取多少次这个对象,取到的都是同一个对象!!

        UserConfig userConfig = context.getBean(UserConfig.class);
        userConfig.doUserConfig();
        System.out.println("userConfig:" + userConfig);

        UserConfig userConfig2 = context.getBean(UserConfig.class);
        userConfig2.doUserConfig();
        System.out.println("userConfig2:" + userConfig2);
        System.out.println(userConfig == userConfig2);

输出结果一样注意这里拿到的对象都是同一个,说明什么,单例模式的体现,这就是Spring用到了其中的一个设计模式,也就是单例模式!

例子演示:

    •    一个类需要创建多个对象时,我们尝试去获取这个对象

@Data
public class UserInfo {
    private Integer id;
    private String name;
    private Integer age;
}
public class BeanConfig {
    @Bean
    public UserInfo u1() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("kun");
        userInfo.setAge(10);
        return userInfo;
    }

    @Bean
    public UserInfo u2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(3);
        userInfo.setName("ji");
        userInfo.setAge(15);
        return userInfo;
    }
}
@SpringBootApplication
public class ExerciseApplication {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ExerciseApplication.class, args);
        UserInfo userInfo = context.getBean(UserInfo.class);
        System.out.println(userInfo);
    }
}

输出结果报错说Bean没有定义,我们虽然加了@Bean注解,但是Spring没有找到

首先我们采用注解的方式让Spring帮我们管理对象时,Spring如何知道我们加没加注解呢?Spring通过扫描的方式,扫描整个项目的方式。但是呢扫描整个项目的时候总不可能真把整个项目中的类和类的方法都过一遍吧,这样效率太低了。所以Spring就不扫描方法了就扫描类如果我们需要Spring扫描方法的话,就需要告诉Spring这个类中有需要它帮我们管理的对象。如何告诉呢?搭配@类注解使用才能将对象正常的存储到 Spring 容器中所以使用方法注解@Bean必须要搭配@类注解使用才能将对象正常的存储到 Spring 容器中!!!

下面我们加入类注解后看看效果如何

@Configuration
public class BeanConfig {
    @Bean
    public UserInfo u1() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("kun");
        userInfo.setAge(10);
        return userInfo;
    }

    @Bean
    public UserInfo u2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(3);
        userInfo.setName("ji");
        userInfo.setAge(15);
        return userInfo;
    }
}

输出结果,当我们加上类注解后,又出现报错报错信息表示定义的Bean不是唯一的。因为我们在获取Bean的时候采用类型获取此时这两个@Bean注解修饰的方法返回类型都是UserInfo,所以就会报错了。由此可以得出使用@Bean注解时,bean的名称和我们的方法名对应!!!

我们修改获取Bean的方式看看,根据方法名称获取

@SpringBootApplication
public class ExerciseApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ExerciseApplication.class, args);
        UserInfo u1 = (UserInfo) context.getBean("u1");
        System.out.println(u1);
    }
}

输出结果,这回正确了获取到了

小结:两个结论,第一个是使用@Bean注解时,bean的名称和我们的方法名对应第二个是一个类型存在多个bean时,我们就不能通过类型获取对象了

补充:还可以通过方法名和类型获取,这样也不用强转了

@SpringBootApplication
public class ExerciseApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ExerciseApplication.class, args);
        UserInfo u1 = context.getBean("u1", UserInfo.class);
        System.out.println(u1);
    }
}

输出结果也是一样的


@Bean传递参数:

给我们刚才的u1方法传入一个参数看看效果

@Configuration
public class BeanConfig {

    @Bean
    public UserInfo u1(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }
}

输出结果,报错信息说需要一个String类型的Bean对象

加一个String类型的Bean对象

@Configuration
public class BeanConfig {

    @Bean
    public String name() {
        return "坤坤";
    }

    @Bean
    public UserInfo u1(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }
}

输出结果

当我们再定义个叫name2的String类型的对象,看看效果

@Configuration
public class BeanConfig {

    @Bean
    public String name() {
        return "坤坤";
    }

    @Bean
    public String name2() {
        return "签哥";
    }

    @Bean
    public UserInfo u1(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }
}

输出结果

我们想想会不会是因为方法顺序的问题呢?

@Configuration
public class BeanConfig {
    
    @Bean
    public String name2() {
        return "签哥";
    }

    @Bean
    public String name() {
        return "坤坤";
    }
    
    @Bean
    public UserInfo u1(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }
}

输出结果,调换一下顺序的效果,没有关系,输出的是还是一样所以跟Bean对象名称有关系

小结:如果需要的Bean的类型对应的对象只有一个就直接赋值如果有多个通过名称进行匹配

给Bean重命名:当变量名重复时

@Configuration
public class BeanConfig {

    @Bean
    public String name() {
        return "坤坤";
    }

    @Bean("u1")
    public UserInfo user(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }

    @Bean
    public UserInfo user() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(3);
        userInfo.setName("ji");
        userInfo.setAge(15);
        return userInfo;
    }
}

输出结果,重命名后就根据重命名后的名称进行获取


扫描路径

上面我们提到使用方法注解@Bean必须要搭配@类注解使用才能将对象正常的存储到 Spring 容器中,也就是告诉Spring哪个类需要它帮我们进行管理,然后它进行扫描,但是呢它的扫描范围是整个包呢还是所有的都要扫描呢?当我们项目引入第三方包时,这些第三方包也属于我们项目的内容了,难道它也要扫描吗?那内容太多了

SpringBoot特点:约定大于配置,如何理解呢?就类似学校的课表都是提前就排好了,开学后我们根据课表上的时间教室去上课,如果没有课表上课都是发通知这太麻烦了。所以这个例子中的课表就是约定,如果没有约定就需要配置了也就是例子中的通知。所以扫描路径是约定大于配置其中之一的体现,下面我们举个例子演示看看约定大于配置的特点

 我们将启动类移到controller包下,看看效果

输出结果,所以上述移动到controller包它只会扫描controller包下的类,其他路径都不扫描,但是呢我们也可以通过一个注解让它去扫描其他路径使用@ComponentScan("指定路径")注解即可实现

@ComponentScan("com.example.exercise.demos")
@SpringBootApplication
public class ExerciseApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ExerciseApplication.class, args);
        BeanConfig bean = context.getBean(BeanConfig.class);
        System.out.println(bean);
    }
}

加入注解后,输出结果正确了

为什么之前没加这个注解它也会扫描默认路径?

默认扫描路径:启动类所在的目录以及其子孙目录

我们去@SpringBootApplication注解看看,会发现原因是启动类的@SpringBootApplication注解,这个注解中默认包含了@ComponentScan注解,我们可以指定路径也可以不指定,不指定的时候它默认扫描当前类的目录以以及其子孙目录

小结:Spring的工作流程它会根据@ComponentScan注解进行扫描,这个注解有个路径,它会根据这个路径进行扫描,扫描什么呢?扫描这个路径下面的所有类上面有没有注解,但不是说所有的都会触及的比如@Data注解,这个注解不属于Spring的注解,它不会处理的,它只处理五大注解,有了五大注解之一它才会去看你的方法有没有使用其他的注解。

注意Spring扫描五大注解的时候不是只扫描五大注解,什么意思呢?例如一个类上有@Controller注解也有@ResponseBody注解,后续会讲解

IoC的具体实现就是Bean的"存"和"取""存"我们通过五大注解以及方法注解@Bean下面来讲解如何"取"


DI详解

 上⾯我们讲解了控制反转IoC的细节,接下来呢,我们讲解依赖注⼊DI的细节,依赖注⼊也被称之为 "对象注⼊", "属性装配", 具体含义需要结合⽂章的上下⽂来理解

关于依赖注入, Spring也给我们提供了三种方式:

1. 属性注入

前面使用到的@Autowired注解,就是属性注入。注意一下属性注入根据类型匹配,和注入的属性名称无关,属于Spring框架提供的注解‼️,看下面的图片

观察以下代码,我们使用@Autowired注解

@Configuration
public class BeanConfig {

    @Bean
    public String name() {
        return "坤坤";
    }

    @Bean
    public UserInfo u1(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }
}
@Controller
public class Demo3Controller {

    @Autowired
    private UserInfo u1;

    public void print() {
        System.out.println(u1);
    }
}

输出结果

@Autowired注解是根据什么匹配到对应的Bean呢,下面这个代码有两个同类型的Bean

@Configuration
public class BeanConfig {

    @Bean
    public String name() {
        return "坤坤";
    }

    @Bean
    public UserInfo u1(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }

    @Bean
    public UserInfo u2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(3);
        userInfo.setName("ji");
        userInfo.setAge(15);
        return userInfo;
    }
}
@Controller
public class Demo3Controller {

    @Autowired
    private UserInfo u1;

    public void print() {
        System.out.println(u);
    }
}

输出结果

换个名称试试

@Controller
public class Demo3Controller {

    @Autowired
    private UserInfo user;

    public void print() {
        System.out.println(user);
    }
}

报错了说明如果一个类型存在多个对象时,优先名称匹配,如果名称都匹配不上就报错


2. 构造方法注入


一个构造方法:

@Controller
public class Demo3Controller {

    @Autowired
    private UserController userController;

    public Demo3Controller(UserController userController) {
        this.userController = userController;
    }

    public void print() {
        userController.doController();
    }
}

输出结果


三个构造方法:

@Controller
public class Demo3Controller {
    private UserInfo u1;
    private UserController userController;

    public Demo3Controller() {

    }

    public Demo3Controller(UserInfo u1, UserController userController) {
        this.u1 = u1;
        this.userController = userController;
    }

    public Demo3Controller(UserController userController) {
        this.userController = userController;
    }

    public void print() {
        userController.doController();
    }
}

输出结果,构造方法是我们在创建对象的时候去调用的,之前我们都是自己通过new去调用构造方法然后创建出一个对象。现在由Spring调用构造方法来创建对象,但是有这么多个构造方法,它不知道要用哪个。Spring默认会去调用无参的构造方法,图中由于userController没有进行初始化,所以报了一个空指针异常

给userController加上@Autowired注解看看效果

@Controller
public class Demo3Controller {
    private UserInfo u1;
    @Autowired
    private UserController userController;

    public Demo3Controller() {

    }

    public Demo3Controller(UserInfo u1, UserController userController) {
        this.u1 = u1;
        this.userController = userController;
    }

    public Demo3Controller(UserController userController) {
        this.userController = userController;
    }

    public void print() {
        userController.doController();
    }
}

输出结果

两个构造方法:

去掉无参构造方法

@Controller
public class Demo3Controller {
    private UserInfo u1;
    @Autowired
    private UserController userController;


    public Demo3Controller(UserInfo u1, UserController userController) {
        this.u1 = u1;
        this.userController = userController;
    }

    public Demo3Controller(UserController userController) {
        this.userController = userController;
    }

    public void print() {
        userController.doController();
    }
}

输出结果,当把无参构造方法删掉后又报了另外的异常,由于Spring默认会去调用无参的构造方法,删掉后它就不知道调用哪构造方法了,所以我们需要使用@Autowired注解指定Spring去调用哪个构造方法

小结:如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法


3. Setter 注入

@Controller
public class Demo3Controller {
    private UserInfo u1;


    private UserController userController;

    public void setUserController(UserController userController) {
        this.userController = userController;
    }

    public void print() {
        userController.doController();
    }
}

输出结果,报了空指针异常

@Controller
public class Demo3Controller {
    private UserInfo u1;
    
    private UserController userController;

    @Autowired
    public void setUserController(UserController userController) {
        this.userController = userController;
    }

    public void print() {
        userController.doController();
    }
}

 加了注解,说明我们的userService注入进来了

使用final修饰

注意:@Autowired注解无法注入一个final修饰的属性,因为final修饰的属性不可变。所以对于final修饰的属性我们要么是在定义时就赋值了,要么是在构造方法中进行赋值


三种注入优缺点分析:

1.属性注入:

优点:简洁,使⽤⽅便

缺点:不能注入final修饰的属性;只能⽤于 IoC 容器


2.构造函数注入:

优点:可以注入final修饰的属性注入的对象不会被修改(因为构造方法是最先被执行的);依赖对象在使用前一定会被初始化好,因为是在类的构造方法中执行的,而类的构造方法是在类加载阶段就会执行的方法;通⽤性好, 构造⽅法是JDK⽀持的,所以更换任何框架,它都是适用的都会注入的

缺点:注⼊多个对象时,代码繁琐

3:Setter注入:

优点:⽅便在类实例之后,重新对该对象进行配置或者注入。优缺点其实都一样,都是方便修改

缺点:不能注入final修饰的属性注入对象可能被修改,因为Setter方法可能会被多次调用


@Autowired存在的问题

当程序中同一个类型有多个对象(Bean)时使用@Autowired可能会报错(一些情况下),什么情况呢?名称对不上

如何解决上述问题呢?属性名和你需要使用的对象名保持一致

1.@Primary注解:使用@Primary注解标识默认的对象

@Configuration
public class BeanConfig {

    @Bean
    public String name() {
        return "坤坤";
    }

    @Primary
    @Bean
    public UserInfo user1(String name) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName(name);
        userInfo.setAge(10);
        return userInfo;
    }

    @Bean
    public UserInfo user2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(3);
        userInfo.setName("ji");
        userInfo.setAge(15);
        return userInfo;
    }
}
@Controller
public class Demo3Controller {

    @Autowired
    private UserInfo userInfo;

    public void print() {
        System.out.println(userInfo);
    }
}

输出结果

2.@Qualifier注解:指定当前要注⼊的bean对象。可以理解为实现了第一种方法来解决问题

@Controller
public class Demo3Controller {

    @Qualifier("user2")
    @Autowired
    private UserInfo userInfo;

    public void print() {
        System.out.println(userInfo);
    }
}

输出结果

注意:@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

3.@Resource注解:指定Bean的名称进行注入

@Controller
public class Demo3Controller {

    @Resource(name = "user2")
    @Autowired
    private UserInfo userInfo;

    public void print() {
        System.out.println(userInfo);
    }
}

输出结果

@Autowird 与 @Resource的区别:

1.@Autowired 是spring框架提供的注解。⽽@Resource是JDK提供的注解

2.(重点)@Autowired默认是按照类型注入的,如果有同一类型有多个对象那就根据名称进行匹配,如果名称也匹配不到就会报错。⽽@Resource是按照名称注入

3.相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean

总结:Bean的存,通过五大注解和方法注解@Bean,使用时Spring默认会给一个默认的名称

 •    五大注解:BeanName 是类名的小驼峰表示(首字母小写),特殊情况如果前两位字母都为大写,则BeanName为类名

•    方法注解@Bean:BeanName就是方法名

如何修改五大注解的BeanName?

    •    直接在五大注解后加个括号里面填写你看得惯的Bean名称,例如@Service("Bean名称"),修改之后,Spring就会使用自定义的Bean名称

如何修改方法注解@Bean的BeanName?

    •    和五大注解后类似,直接在方法注解后加个括号里面填写你看得惯的Bean名称,例如@Bean("Bean名称"),并且可以有多个Bean名称,但是一个名称对应一个Bean

以上便是本章SpringIoC和DI的内容,这个知识点挺重要的属于Spring的核心之一需要好好吸收,我们下一章再见💕

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值