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

【Spring 全家桶】 Spring IOC DI 保姆式教学, 教你不用new也能获取到对象的依赖注入方式, 建议收藏 . . .

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在这里插入图片描述

引言

在编程的浩瀚宇宙中,Spring IoC犹如一颗璀璨的星辰,引领我们走向更加高效、灵活的开发之路。它不仅仅是一种设计模式,更是编程思想的一次革新。通过控制反转和依赖注入,Spring IoC让我们从繁琐的对象管理中解脱出来,专注于业务逻辑的实现,让代码更加简洁、易于维护。它如同一把钥匙,打开了编程世界的新大门,让我们在编程的旅途中游刃有余,畅享编程的乐趣。

目录

  1. Spring IOC

  2. Bean 存储的注解

  3. 依赖注入

一. Spring IOC

1. Spring IOC 初识

在这里插入图片描述

IOC 指的是一种设计模式, 也称之为 依赖注入, 一方面

Spring IOC 指的是:控制反转, 具体来说就是: 由原先我们 new 对象 来调用接口转变成 把 对象的单个实例 交给 第三方 Spring的 bean 配置 来管理。

Spring DI 就是把 Spring 中的管理的对象, 注入到需要使用的 变量调用

怎么样实现对于对象的 Bean 存储, Spring 提供了 丰富的注解

常用的类注解

@Controller

@Service

@Component

@Repository

@Configuration

添加了类注解之后, 这个 类实例化出来的对象就交给Spring 来管理了。

对于我们只是想调用其中的方法, Spring 还提供了对应的方法注解:

@Bean

小伙伴们先混个眼熟哦, 这些内容小编会在下面内容中, 详细展开讲解

2. Spring IOC 的优势

Spring IOC 的优势有:

在这里插入图片描述

  • 解耦合: 由相互调用 ,互相的关联性就比较高, 到现在都由Spring 来管理,接口和接口之间的依赖程度就比较低 , 耦合性就降低了很多。

  • 提高代码的可测试性: 由于 对象和对象之间都是由 Spring 来管理的 , 可以直接测试单个组件, 无须关心组件和组件之间的关系。

鱼式疯言

补充说明

以造汽车为例:

传统的开发 来说, 汽车需要什么部件, 我们才造什么部件, 从而组合成一辆汽车, 这样的耦合性也很高, 不同的汽车也可能需要的是不同的组件

IOC 的角度 就不需要这样想: 我们把每个汽车部件,都变成 一个一个小工厂 , 也就是都交给 Spring 来管理 , 如果需要的话, 就从 这个工厂中直接拿这些部件就能更高效的进行。

二. Bean 存储的注解

1. 类注解的介绍

在上面内容中, 我们初识了以下五种类注解:

  • @Controller

  • @Service

  • @Component

  • @Repository

  • @Configuration

其实这些类注解的作用没有本质区别, 都是将对应的类的实例化交给 Spring 的Bean 来管理。

但是在开发中, 还是有一定的规范的, 不是随意选择的

在这里插入图片描述

如上图, 还是回到我们这张图来说:

<1>. @Controller

import org.springframework.stereotype.Controller;

@Controller
public class ControllerDemo {

//    这里就是控制器的控件, 用于客户端访问的入口
    	public void Controller() {
        	System.out.println("hello controller");
        }
}
  • 前端通过 Controller 层 来访问后端, 所以在 Controller 层的那个类 中, 就需要加上 @Controller 或者 @RestController

鱼式疯言

补充说明:

@RestController = @Controller + @ResponseBody

<2>. @Service

import org.springframework.stereotype.Service;

@Service
public class ServiceDemo {
//    提供具体的业务逻辑和服务的一个部件
        public  void service() {
            System.out.println("go go ServiceDemo");
        }
}
  • @Service 对应着后端提供 服务的一层, 通过这一层来处理具体的业务逻辑相关 的功能。

<3>. @Repository

import org.springframework.stereotype.Repository;

@Repository
public class RepositoryDemo {
    public void repository() {

        System.out.println("oh my repositoryDemo");

	}
}
  • 用于 连接数据库的一层 : 使用 @Repository 来标明这是 数据层

<4>. @Component 与 @Configuration


import org.springframework.stereotype.Component;

@Component
public class ComponentDemo {
//    这里用于其他部件的 的一种父类成员

        public  void component() {
            System.out.println("this is my ComponentDemo");
        }

}

import org.springframework.stereotype.Configuration;

@Configuration
public class ConfigurationDemo {

//    处理一些配置相关的包
    public void configurationDemo() {

        System.out.println("ConfigurationDemo");
    }
}

剩下的就是 配置和组件 相关的, 一般而言, 配置使用 @Configuration 注解来标明组件使用 @Component 来标明

但是这两个注解没有特定的规范, 有时也可以反过来使用, 这里 没有很大的区别

鱼式疯言

总结概括

小伙伴们只需要记住:

控制层@Controller / @RestController

服务层@Service

数据层@Repository

配置与组件层@Component / @Configuration

2. 类注解的使用以及启动类中的调用

加入好类注解之后, 就加入到Spring 中管理了,就加入到Bean中 了

这时就可以在启动类中进行通过Spring 获取该对象,获取方式有三种:

  • . 对象引用名 + 类对象

  • . 对象引用名

  • . 类对象

<1>. 对象引用名 + 类对象

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringiocApplication {


//    在启动类中获取对应的对象属性
    public static void main(String[] args) {

        /**
         * 启动类获取对象和属性_test
         */

//        获取上下文
       ApplicationContext context =  SpringApplication.run(SpringiocApplication.class, args);


        //  通过类对象和标准名字一起获取
        ConfigurationDemo configurationDemo = context.getBean("configurationDemo", ConfigurationDemo.class);
        configurationDemo.configurationDemo();
}

在这里插入图片描述

如上图, 在启动类中:

首先, 通过 ApplicationContext 类型来接收启动类运行之后的返回值, context 包含所有的Bean 的信息。

然后,操作 context 通过 getBean() , 并在参数列表中 加入 “configurationDemo”, ConfigurationDemo.class 来获取 ConfigurationDemo 对象

最终 调用该对象的方法, 输入打印信息

<2>. 类对象

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.demo2.springioc.controller.ControllerDemo;

@SpringBootApplication
public class SpringiocApplication {


//    在启动类中获取对应的对象属性
    public static void main(String[] args) {

        /**
         * 启动类获取对象和属性_test
         */

//        获取上下文
       ApplicationContext context =  SpringApplication.run(SpringiocApplication.class, args);


//       通过上下文的类对象来获取
        ControllerDemo controllerDemo = context.getBean(ControllerDemo.class);
        controllerDemo.Controller();
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;



@RestController
@Controller
@ResponseBody
public class ControllerDemo {

    public void Controller() {

        System.out.println("hello controller");

    }
}

在这里插入图片描述

如上图, 通过 类名.class 来获取类对象, 通过 类对象来获取 Bean 成员。

<3>. 对象引用名获取

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.demo2.springioc.repository.RepositoryDemo;


@SpringBootApplication
public class SpringiocApplication {


//    在启动类中获取对应的对象属性
    public static void main(String[] args) {
    //        通过类标准名字来获取
        RepositoryDemo repositoryDemo = (RepositoryDemo)context.getBean("repositoryDemo");
        repositoryDemo.repository();
//
}
import org.springframework.stereotype.Repository;

@Repository
public class RepositoryDemo {
    public void repository() {

        System.out.println("oh my repositoryDemo");

    }

}

在这里插入图片描述

这里像上面一样通过调用 getBean() , 参数类表中使用 repositoryDemo 这样的对象引用名来获取。

注意这里的 对象引用名一定要规范 , 就是说类名 RepositoryDemo 中的首字母转化为小写: repositoryDemo

鱼式疯言

补充说明

获取到的对象, 其实是同一个对象 , 如下图,也就是前面小编讲解过的 单例模式

在这里插入图片描述


小伙伴有没有思考过, 如果这个类是不可修改的,也就是不能加注解的文本, 那么我们该怎么获取到Bean 对象呢?

聪明的程序猿肯定都考虑到了, 下面我们就来看看呗~

3. Bean 方法注解

@Bean 是作用方法的一种存储对象的注解, 专门用于对于使用方法实例化存储的Bean 对象。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class BeanDemo {
    @Bean
    public String getStr1() {
        return "str1";
    }

    @Bean
    public String getStr2() {
        return "str2";
    }

}

在这里插入图片描述

如上图, 小编在这里通过方法, 实例化了两个String对象, 通过Spring 来管理交给了Bean 。

首先, 创建如上方法, 在方法中 创建对象并返回

然后,加入@Bean , 交给Spring 管理

最后再 启动类 中使用 三种方式调用

这里小伙伴们要注意一点哦~

在这里插入图片描述

如上图,

当使用 类对象 来寻找 Bean 时, 就会出现 不唯一对象 的情况, 因为在 Spring 中已经管理了很多个String 对象

Spring 无法辨别是 哪个String 对象 , 就会 抛出异常

所以第二种使用类对象调用的方式, 一般适用于 只含有一个对象 的情况下使用 。

鱼式疯言

补充说明

  1. @Bean 中的name = 方法名
  1. 使用 第一种和第三种方式获取对象 时, 参数 name 填入的是方法名, , 填入方法名 也就是获取方法名中实例化的 Bean 的对象
  1. 在使用 @Bean 注解之前 , 小伙伴们一定要注意加上 Bean 的类注解, 否则也会 抛出异常 (如上述代码,小编加入了 @Configuration 这个注解)
  1. 一般而言, @Bean 修饰的方法为 public , 否则很有可能会 出现异常 哦~

小伙伴有没有思考过这样的问题, 为啥我们只能在启动类中使用这些 Bean 对象呢?

我们是否可以在其他的类中使用这些 Bean 对象呢?

答案是: 可以的

下面的 依赖注入 将带着小伙伴一起揭开这神秘的面纱。

三. 依赖注入

依赖注入, 就是从 Spring 管理 的对象来 获取对象 , 也称之为 Spring DI

获取对象的方式, 常用的有两种:

  • @Autowired

  • @Resource

1. @Autowired

注入方式有三种, 分别是:

  • 属性注入

  • 构造方法注入

  • 成员方法注入

<1>. 注入属性

import com.demo2.springioc.model.UserInfo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Data
@Component
public class AutowiredDemo {
    @Autowired
   public  UserInfo userInfo;
}

在这里插入图片描述

鱼式疯言

补充说明

  1. 对于 @Autowired 而言, 不可注入属性时, 不可注入final 修改的成员 变量。
  1. @Autowired 不仅是注入 @Bean 修饰的Bean 实例 , 也可以注入 前面讲解的五大注解修饰 的 Bean 实例对象。

<2>. 注入构造方法

import com.demo2.springioc.model.UserInfo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Data
@Component
public class AutowiredDemo {
   public  UserInfo userInfo;

    @Autowired
    public AutowiredDemo(UserInfo userInfo) {
        this.userInfo = userInfo;
    }
}

在这里插入图片描述

<3> .注入成员方法

import com.demo2.springioc.model.UserInfo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Data
@Component
public class AutowiredDemo {
   public  UserInfo userInfo;


    @Autowired
    public UserInfo getUserInfo(UserInfo userInfo) {
        this.userInfo = userInfo;
        return userInfo;
    }
}

在这里插入图片描述

2. @Resource

import com.demo2.springioc.model.UserInfo;
import jakarta.annotation.Resource;
import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@Component
public class AutowiredDemo {
   public  UserInfo userInfo;


    @Resource
    public UserInfo getUserInfo(UserInfo userInfo) {
        this.userInfo = userInfo;
        return userInfo;
    }
}

在这里插入图片描述

如果是 该对象只含有一个 Bean 的话, @Resource = @Autowired

但是如果是 多个Bean , 两者就会出现 使用方式上的不同

3. 多个Bean

在这里插入图片描述
如上图:当出现 多个Bean 时, 这里的使用 @Autowired 后, Spring 就无法识别出该 注入哪个对象 了。

那么 @Autowired@Resource 都有 自己的方式来确定该注入哪个依赖

@Autowired + @Qualifier

import com.demo2.springioc.model.UserInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
class  BeanDemo1{
    @Bean
    public UserInfo userInfo1() {
        return new UserInfo(19,"帅哥~");
    }

        @Bean
    public UserInfo userInfo2() {
        return  new UserInfo(88,"奶奶");
    }

}
import com.demo2.springioc.model.UserInfo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Data
@Component
public class AutowiredDemo {
   public  UserInfo userInfo;


    @Autowired
    public UserInfo getUserInfo(@Qualifier("userInfo2") UserInfo userInfo) {
        this.userInfo = userInfo;
        return userInfo;
    }
}

在这里插入图片描述

如上图, 如果出现多个Bean 的话, 这里就需要 @Qualifier 在内部指定 方法名 , 来获取对应的 Bean

@Resource 指定名称

import com.demo2.springioc.model.UserInfo;
import jakarta.annotation.Resource;
import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@Component
public class AutowiredDemo {
   public  UserInfo userInfo;


   @Resource(name = "userInfo1")
    public UserInfo getUserInfo(UserInfo userInfo) {
        this.userInfo = userInfo;
        return userInfo;
    }
}

在这里插入图片描述

如上图, 这里我们只需要在 Resource () 中加入 name = 方法名 , 用于指定其中特定的 Bean

鱼式疯言

总结概括

  1. 如果是 唯一的Bean 而言
    @Resource = @Autowired
  1. 如果是多个 Bean 而言
    @Resource = @Qualifier + @Autowired

4. @Autowired 与 @Resource 的区别(常考面试题)

主要有区别有三:

  1. 适用环境@AutowiredSpring 实现的注解,主要用在 Spring 的框架 下 , @Resource 是 JDK 实现的注解, 不仅在 Spring 能使用, 在 其他的Java 环境下也能使用
  1. 依赖注入的实现方式@Autowired 根据类型自动装配 , 一般而言

@Autowired 根据类型先查找Bean 的实例, 如果没有找到就再根据 默认的名称 来查找Bean的 实例

@Resource 先根据 默认名称 查找 Bean的实例 , 如果没有找到再根据 指定的类型 来查找 。

  1. 默认行为: @Autowired 找不到匹配的依赖 , 会 抛出异常@Resource 找不到匹配, 默认行为可能会根据 具体实现而不同

总结

  • . Spring IOC : 初步理解 Spring IOC 是从直接new 对象调用到控制反转到第三方管理 , 注入依赖的一种设计模式 。

  • . Bean 存储的注解 : 理解五大类注解的本质都是交给 Spring 管理的 Bean 实例 , 并且学习了 @Bean 的方法注解的使用 , 以及使用 启动类是来获取对应的Bean 实例的多种方式

  • . 依赖注入 : 学习 @Autowired@Resource 的基本使用的 多种方式 , 并且理解 两者的区别

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述


http://www.kler.cn/a/452728.html

相关文章:

  • C语言基础:指针(数组指针与指针数组)
  • cad学习 day7-9
  • 每天40分玩转Django:Django静态文件
  • 简述Git中如何将一个新增文件添加到本地仓库?
  • Linux之ARM(MX6U)裸机篇----2.汇编LED驱动实验
  • 《Mycat核心技术》第06章:Mycat问题处理总结
  • BP分类-反向传播神经网络(Backpropagation Neural Network)
  • qt实现socketCAN
  • hive常用函数有哪些
  • HCIE-day9-OSPF
  • 亚远景-ISO 21434标准涵盖了哪些方面?
  • 基于深度学习(HyperLPR3框架)的中文车牌识别系统-搭建开发环境
  • 01.HTTPS的实现原理-HTTPS的概念
  • 【华为OD-E卷-MVP争夺战 100分(python、java、c++、js、c)】
  • Chrome+Postman做接口测试
  • 海格通信嵌入式面试题及参考答案
  • Ubuntu系统下 npm install -g tauri 报错问题处理
  • pnpm、Yarn 和 npm 的区别?
  • MySQL用表组织数据
  • 面试经典问题 —— 最大/小前K个数问题(top - K)问题
  • postgresql ERROR: cannot drop the currently open database
  • Java处理视频思路
  • 【接口自动化连载】使用yaml配置文件自动生成接口case
  • Postman最新接口自动化持续集成
  • 虚拟机桥接模式网络连接不上解决方法
  • SQL server学习10-数据库编程(中)