【Java EE】Spring IOCDI

Spring IOC & DI

文章目录

  • Spring IOC & DI
    • 一、Spring是什么?
    • 二、IOC(控制反转)
      • 2.1 通俗理解
      • 2.2 造汽车的例子理解IOC
      • 2.3 IOC详解
        • 1. 获取Bean
        • 2. 方法注解——@Bean
          • 1. 应用场景:
          • 2. 应用方法:
          • 3. 注意要点:
      • 特别注意:
    • 四、DI
      • 4.1 属性注入
        • 使用方法
      • 4.2 构造方法注入
        • 使用方法
      • 4.3 在setter方法注入
        • 使用方法
      • 4.4三种注⼊优缺点分析
      • 4.5 @Autowired出现多个同类型Bean的情况
        • 原因:
        • 解决方法:
          • 1. 使用 `@Primary` 指定默认匹配的项目
          • 2. 使用`autowireCandidate = false`去除默认匹配
          • 3. 使用 `@Resource(name="**")`对于特定名称的Bean进行注入
      • 4.6 @Autowired和@Rescource的区别

一、Spring是什么?

Spring是一个开发的框架,包含了很多的依赖,比如Spring MVC, Spring Boot等,这些让我们开发变得容易,可以说,Spring是一个包含很多工具方法的容器。

二、IOC(控制反转)

2.1 通俗理解

Inversio of Control ,也就是说,Spring是一个 “控制反转” 的容器。

控制反转就是让一个事物的控制权交由其他人。

2.2 造汽车的例子理解IOC

造汽车的流程:

在这里插入图片描述

代码:
汽车类:

package com.example.springioc.v1;

public class Car {
    // 汽车依赖于框架
    private Frame frame;

    public Car() {
        frame = new Frame();
        System.out.println("汽车安装框架中...");
    }
}

框架类:

package com.example.springioc.v1;

public class Frame {
    // 框架依赖于底盘
    private Bottom bottom;
    public Frame() {
        bottom = new Bottom();
        System.out.println("框架安装底盘中...");
    }
}

底盘类:

package com.example.springioc.v1;

import jdk.jfr.Frequency;

public class Bottom {
    // 底盘依赖于轮胎
    private Tire tire;
    // 有了尺寸的需求,需要进行传参
    public Bottom(int size) {
        tire = new Tire(size);
        System.out.println("底盘安装轮胎中...");
    }
}

轮胎类:

package com.example.springioc.v1;

public class Tire {
    public Tire() {
        System.out.println("打造默认尺寸轮胎中...");
    }
}

运行结果:

在这里插入图片描述

这种代码架构,每个类的控制权都在调用他的那一方中,调用的一方创造了怎样的他,那他就是怎样的。

如果想要更换任意尺寸的轮胎,那就需要传递一个size参数,此时要依次对于代码做修改。

首先是轮胎类,需要增加 size 属性,但是这样最上层的 Car 类并不能够选择自己想要的尺寸,仍然需要对于控制着 Tire 的Bottom进行添加参数以便Frame能够添加参数,这样依赖,Frame也得添加size参数,Car 也需要。

最终代码(对于每一级都添加了size参数):

汽车类:

package com.example.springioc.v1;

public class Car {
    // 汽车依赖于框架
    private Frame frame;

    // 对于汽车类添加了size参数构造
    public Car(int size) {
        frame = new Frame(size);
        System.out.println("汽车安装框架中...");
    }
}

框架类:

package com.example.springioc.v1;

public class Frame {
    // 框架依赖于底盘
    private Bottom bottom;
    public Frame(int size) {
        bottom = new Bottom(size);
        System.out.println("框架安装底盘中...");
    }
}

底盘类:

package com.example.springioc.v1;

import jdk.jfr.Frequency;

public class Bottom {
    // 底盘依赖于轮胎
    private Tire tire;
    public Bottom(int size) {
        tire = new Tire(size);
        System.out.println("底盘安装轮胎中...");
    }
}

轮胎类:

package com.example.springioc.v1;

public class Tire {
    // 轮胎的大小
    private Integer size;

    public Tire() {
        System.out.println("打造默认尺寸轮胎中...");
    }
    public Tire(int size) {
        System.out.println("打造"+size+"号的轮胎中...");
    }
}

显而易见,这样的代码架构维护起来非常臃肿
每一下级的控制权都由上一级保管,如果对于下一级的需求发生了变化,那么这就需要改动所有的类。(比如:如果现在用户需要对于轮胎的轮毂进行制定,那就还需要给Tire的构造函数增添一个 style 属性,如果还有颜色等的需求,那就还得一直加;只加Tire一个类的还好,因为每一上级都直间或者间接依赖于这个Tire,每一个类都需要进行修改,耦合度非常高。)

所以就需要 “控制反转” 思想,将整个控制反转:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

修改后的代码:

package com.example.springioc.v2;

import com.example.springioc.v1.Frame;

public class Main {
    static class Tire {
        int size;

        public Tire(int size) {
            this.size = size;
            System.out.println("打造"+size+"号轮胎...");
        }
    }
    static class Bottom{
        Tire tire;

        public Bottom(Tire tire) {
            this.tire = tire;
            System.out.println("打造底盘...");
        }
    }
    static class Framework {
        Bottom bottom;

        public Framework(Bottom bottom) {
            this.bottom = bottom;
            System.out.println("打造框架...");
        }
    }

    static class Car {
        Framework framework;

        public Car(Framework framework) {
            this.framework = framework;
            System.out.println("打造汽车...");
        }
    }

    public static void main(String[] args) {
        Tire tire = new Tire(1);
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
    }
}

这样一来,如果用户对于轮胎有新的需求,那也只需要修改轮胎这一个类,完成了整个代码的解耦。

也就是说,我们将控制权转让给了Tire自己,Tire的上级类不再享有控制权,传来什么Tire,就用什么。

2.3 IOC详解

控制反转之后,对象进入Spring容器就会变成Bean,也就是说,Spring中的对象都叫做Bean。

1. 获取Bean
  1. 注册Bean:使用五大注解,让Spring Boot能够发现@Bean
  2. 主要方法:使用 context 的 getBean() 进行获取
  3. 得到的Bean就相当于从Spring Boot中取到了这个对象

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 方法注解——@Bean
1. 应用场景:
  1. 当对于外部类的方法,无法通过修改源码进行注册Bean,所以可以使用Spring的@Import注解来导入一个配置类,在这个配置类中你可以使用@Bean注解来声明这个外部类作为一个Bean,并对其进行配置。

  2. 如果一个类中需要多个实例,可以使用@Bean对于实例进行别名命名(value和name),以示区分。

2. 应用方法:
		/**
         * 使用@Bean的演示
         */
        // 使用类,获得整个类的Bean
        User bean1 = context.getBean(User.class);
        System.out.println(bean1);
        // li4是使用name属性定的别名
        User bean2 = (User) context.getBean("li4");
        System.out.println(bean2);
        // user3是方法的名字
        User bean3 = (User) context.getBean("user3");
        System.out.println(bean3);
3. 注意要点:
  1. @Bean是方法级的注解
  2. 需要配合类注解进行使用
  3. 使用value和name属性可以命名别名
  4. Bean的名字就是方法的名字
  5. autowireCandidate 可以消除:当有多个能够匹配的实例的时候,排除这个实例

特别注意:

@ComponentScan 可以定义Spring的扫描路径。

使用方法:

@ComponentScan({"com.example.springioc.bean_test"})

直接在()中使用{}定义路径。

四、DI

DI就是依赖注入。

4.1 属性注入

使用 @Autowired 注入。

使用方法
package com.example.springioc.di_test.controller;

import com.example.springioc.di_test.service.TireSeervice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class TireController {
    @Autowired
    TireSeervice tireSeervice;
    public void doTire() {
        System.out.println("成功调用轮胎控制器...");
        tireSeervice.doTire();
    }
}

使用 @Autowired 将service属性注入到控制器中。

package com.example.springioc.di_test.service;

import com.example.springioc.di_test.model.Tire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TireService {
    @Autowired
    Tire tire;
    public void doTire() {
        tire.setSize(12);
        tire.setColor("红");
        System.out.println("制作"+tire.getSize()+"号"+tire.getColor()+"色的轮胎");
    }
}

同时在服务类中将需要的轮胎对象注入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.2 构造方法注入

将构造方法使用 @Autowired 注入。

使用方法
package com.example.springioc.di_test2.service;

import com.example.springioc.di_test2.model.Tire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TireService {
    Tire tire;

    @Autowired //构造函数上注入
    public TireService(Tire tire) {
        this.tire = tire;
        tire.setSize(12);
        tire.setColor("红");
    }

    public void doTire() {
        System.out.println("制作"+tire.getSize()+"号"+tire.getColor()+"色的轮胎");
    }

}

在服务类的构造方法中使用@Autowired 中注入。

package com.example.springioc.di_test2.controller;

import com.example.springioc.di_test2.service.TireService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class TireController {
    TireService tireService;

    @Autowired //构造函数上注入
    public TireController(TireService tireService) {
        this.tireService = tireService;
    }

    public void doTire() {
        System.out.println("成功调用轮胎控制器...");
        tireService.doTire();
    }

}

在控制类的构造方法使用@Autowired 中注入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.3 在setter方法注入

将构造方法使用 @Autowired 注入。

使用方法
package com.example.springioc.di_test3.service;

import com.example.springioc.di_test3.model.Tire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class TireService {
    Tire tire;

    @Autowired //set方法上注入
    public void setTire(Tire tire) {
        this.tire = tire;
        tire.setSize(1);
        tire.setColor("green");
    }


    public void doTire() {
        System.out.println("制作"+tire.getSize()+"号"+tire.getColor()+"色的轮胎");
    }

}

在服务类的setter方法中使用@Autowired 中注入。

package com.example.springioc.di_test3.controller;

import com.example.springioc.di_test3.model.Tire;
import com.example.springioc.di_test3.service.TireService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class TireController {
    private TireService tireService;

    @Autowired //set方法上注入
    public void setTireService(TireService tireService) {
        this.tireService = tireService;
    }

    public void doTire() {
        System.out.println("成功调用轮胎控制器...");
        tireService.doTire();
    }

}

在控制类的setter方法使用@Autowired 中注入。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.4三种注⼊优缺点分析

  1. 属性注⼊
    ◦ 优点: 简洁,使⽤⽅便;
    ◦ 缺点:
    ▪ 只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指
    针异常)
    ▪ 不能注⼊⼀个Final修饰的属性

  2. 构造函数注⼊(Spring 4.X推荐)
    ◦ 优点:
    ▪ 可以注⼊final修饰的属性
    ▪ 注⼊的对象不会被修改
    ▪ 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法
    是在类加载阶段就会执⾏的⽅法.
    ▪ 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的
    ◦ 缺点:
    ▪ 注⼊多个对象时, 代码会⽐较繁琐

  3. Setter注⼊(Spring 3.X推荐)
    ◦ 优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
    ◦ 缺点:
    ▪ 不能注⼊⼀个Final修饰的属性
    ▪ 注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险

4.5 @Autowired出现多个同类型Bean的情况

会发生报错:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

控制器类:

package com.example.springioc.autowired_test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class TestController {
    @Autowired// 有两个String类型的Bean
    String name;

    public void sayHi() {
        System.out.println(name);
    }
}

组件类:

package com.example.springioc.autowired_test;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class BeanConfig {
    @Bean
    public String test1() {
        return new String("zhang3");
    }
    @Bean
    public String test2() {
        return new String("li4");
    }
}

可以看出组件中有两个String类型的Bean。

原因:

@Autowired不知道选择哪个Bean进行注入,发生了冲突,需要解决这个冲突。

解决方法:
1. 使用 @Primary 指定默认匹配的项目
2. 使用autowireCandidate = false去除默认匹配
3. 使用 @Resource(name="**")对于特定名称的Bean进行注入

在这里插入图片描述

在这里插入图片描述

4.6 @Autowired和@Rescource的区别

  1. @Autowired 是spring提供的注解,@Rescource是Java EE提供的注解

  2. @Autowired按照默认规则进行注入,但是@Rescource根据名称注入,有更多的选项。

    默认规则:
    在这里插入图片描述

  3. @Qualifer 优先级高于@Autowired

  4. @Autowired执行流程

    按照类型查找,如果只查到一个,就直接注入
    如果没有查到,报错
    如果查找到了多个,根据名称查找,查找到了,注入
    没有查找到,抛异常

  5. @Qualifier
    按照名称和类型去查

  6. @Qualifier +@Autowired
    直接按照类型+Qualifier的名称去查如果@Autowired对应的类型,只有一个,但是名称和@Qualifier名称不一样,注入也是失败的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/773640.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Superset超火的企业级可视化BI分析工具

Superset,听起来就像是超级集合,确实,它几乎集合了所有你需要的数据功能。简单说,它就是一个现代化、功能强大的数据可视化工具。 它支持各种数据库,有着丰富的可视化选项,可以用来创建漂亮的数据仪表盘&a…

【数据清洗中分段线性插值法原理】

数据清洗中分段线性插值法原理 一、什么是分段线性插值法?二、分段线性插值法的数学原理三、分段线性插值法的应用步骤1. 引入库2. 创建示例数据3. 应用分段线性插值法4. 可视化插值结果 一、什么是分段线性插值法? 分段线性插值法通过在已知数据点之间…

【C语言】return 关键字

在C语言中,return是一个关键字,用于从函数中返回值或者结束函数的执行。它是函数的重要组成部分,负责将函数的计算结果返回给调用者,并可以提前终止函数的执行。 主要用途和原理: 返回值给调用者: 当函数执…

[leetcode hot 150]第一百一十七题,填充每个节点的下一个右侧节点

题目: 给定一个二叉树: struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL 。 初始状态下&#x…

【图卷积网络】GCN基础原理简单python实现

基础原理讲解 应用路径 卷积网络最经典的就是CNN,其 可以提取图片中的有效信息,而生活中存在大量拓扑结构的数据。图卷积网络主要特点就是在于其输入数据是图结构数据,即 G ( V , E ) G(V,E) G(V,E),其中V是节点,E是…

C语言 指针和数组——指针的算术运算

目录 指针的算术运算 指针加上一个整数 指针减去一个整数 指针相减 指针的关系比较运算 小结 指针的算术运算 指针加上一个整数 指针减去一个整数 指针相减 指针的关系比较运算 小结  指针变量 – 指针类型的变量,保存地址型数据  指针变量与其他类型…

关于SQL NOT IN判断失效的情况记录

1.准备测试数据 CREATE TABLE tmp_1 (val integer);CREATE TABLE tmp_2 (val integer, val2 integer);INSERT INTO tmp_1 (val) VALUES (1); INSERT INTO tmp_1 (val) VALUES (2); INSERT INTO tmp_2 (val) VALUES (1); INSERT INTO tmp_2 (val, val2) VALUES (NULL,0);2.测…

swiftui中设置建议最多5个tabItem项,多个tabItem项会被自动折叠起来

在swiftui中设置底部的菜单栏的时候,最多建议设置5个,如果超过了,会被自动折叠到More中,点击More就会出现类似list的样式显示,不是很友好。 最多按照5个默认设置的话,就会正常全部显示出来: 测…

(七)glDrawArry绘制

几何数据&#xff1a;vao和vbo 材质程序&#xff1a;vs和fs(顶点着色器和片元着色器) 接下来只需要告诉GPU&#xff0c;使用几何数据和材质程序来进行绘制。 #include <glad/glad.h>//glad必须在glfw头文件之前包含 #include <GLFW/glfw3.h> #include <iostrea…

红海云签约海新域集团,产业服务运营领军企业加速人力资源数字化转型

北京海新域城市更新集团有限公司&#xff08;以下简称“海新域集团”&#xff09;是北京市海淀国有资产投资集团有限公司一级监管企业&#xff0c;致力于成为国内领先的产业服务运营商。集团积极探索城市和产业升级新模式&#xff0c;通过对老旧、低效等空间载体重新定位规划、…

2024年新考纲下的PMP考试有多难?全面解读!

一、PMP考试是什么&#xff0c;PMP证书有什么用&#xff1f; PMP&#xff08;Project Management Professional&#xff09;是指项目管理专业人士。PMP考试由美国PMI发起&#xff0c;旨在严格评估项目管理人员的知识和技能&#xff0c;以确定其是否具备高品质的资格认证。 PM…

c进阶篇(四):内存函数

内存函数以字节为单位更改 1.memcpy memcpy 是 C/C 中的一个标准库函数&#xff0c;用于内存拷贝操作。它的原型通常定义在 <cstring> 头文件中&#xff0c;其作用是将一块内存中的数据复制到另一块内存中。 函数原型&#xff1a;void *memcpy(void *dest, const void…

手机如何充当电脑摄像头,新手使用教程分享(新)

手机如何充当电脑摄像头&#xff1f;随着科技的发展&#xff0c;智能手机已经成为我们日常生活中不可或缺的一部分。手机的摄像头除了拍摄记录美好瞬间之外&#xff0c;其实还有个妙用&#xff0c;那就是充当电脑的摄像头。手机摄像头充当电脑摄像头使用的话&#xff0c;我们就…

上位机图像处理和嵌入式模块部署(mcu 项目1:固件编写)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 说完了上位机的开发&#xff0c;接下来就是固件的开发。前面我们说过&#xff0c;目前使用的开发板是极海apm32f103的开发板。它自身包含了iap示例…

Linux - Shell 以及 权限问题

目录 Shell的运行原理 Linux权限问题 Linux权限的概念 如何实现用户账号之间的切换 如何仅提升当前指令的权限 如何将普通用户添加到信任列表 Linux权限管理 文件访问者的分类&#xff08;人&#xff09; 文件类型和访问权限&#xff08;事物属性&#xff09; 文件权限值的表…

【linux高级IO(一)】理解五种IO模型

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux高级IO 1. 前言2. 重谈对…

Linux之文本三剑客

Linux之三剑客 Linux的三个命令,主要是用来处理文本,grep,sed,awk,处理日志的时候使用的非常多 1 grep 对文本的内容进行查找 1) 基础用法 语法 grep 选项 内容|正则表达式 文件选项: -i 不区分大小写 -v 排除,反选 -n 显示行号 -c 统计个数查看文件里包含有的内容 [roo…

【项目管理】项目风险管理(Word原件)

风险和机会管理就是在一个项目开发过程中对风险进行识别、跟踪、控制的手段。风险和机会管理提供了对可能出现的风险进行持续评估&#xff0c;确定重要的风险机会以及实施处理的策略的一种规范化的环境。包括识别、分析、制定处理和减缓行动、跟踪 。合理的风险和机会管理应尽力…

【TB作品】体重监控系统,ATMEGA16单片机,Proteus仿真

机电荷2018级课程设计题目及要求 题1:电子称重器设计 功能要求: 1)开机显示时间(小时、分)、时分可修改; 2)用滑动变阻器模拟称重传感器(测量范围0- 200g),数码管显示当前重量值,当重量值高于高 值时,红灯长亮; 3)当重量值低于低值时,黄灯长亮; 4)当重量值在正常值时,绿灯亮; 5…

Exploting an API endpoiint using documentation

HTTP request methods https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods 第一步:burp抓包刷新页面 httphistory中只能看到两个记录,可以看下Response,是HTML页面,说明这里有HTML页面 ,但是没有发现特定的API接口。 第二步:用户登录 转到用户登录的功能点处…
最新文章