【Java EE】Spring IOCDI

news2024/11/17 9:48:04

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根据名称注入,有更多的选项。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot+vue+uniapp的超市售货管理平台

开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…

工具网源码|计算某一天是当年的第几周,第几天,黄历工具

源码简介: 工具网源码|计算某一天是当年的第几周,第几天,黄历工具,无文章系统,全站同过算法实现,并在前台展示,页面多,很适合seo。 演示站: https://dijizhou.wengu8.com…

从项目中学习Bus-Off的快慢恢复

0 前言 说到Bus-Off,大家应该都不陌生,使用VH6501干扰仪进行测试的文章在网上数不胜数,但是一般大家都是教怎么去干扰,但是说如何去看快慢恢复以及对快慢恢复做出解释比较少,因此本文以实践的视角来讲解Bus-Off的快慢恢…

期末复习---程序填空

注意&#xff1a; 1.数组后移 *p *(p-1) //把前一个数赋值到后一个数的位置上来覆盖后一个数 2.指针找最大字符 max *p while( *p){ if( max< *p) { max*p; qp;/ 用新的指针指向这个已经找到的最大位置&#xff1b;!!!!!!!!! } p; //因为开始没有next &#xff…

网络爬虫(二) 哔哩哔哩热榜高频词按照图片形状排列

我们有时候需要爬取结果生成为自定义的词云图 生成自定义的词云图通常需要以下步骤&#xff1a; 1. 爬取数据&#xff1a;使用爬虫工具或库&#xff0c;如requests、BeautifulSoup等&#xff0c;可以爬取网页、论坛、社交媒体等平台上的文本数据。 2. 数据预处理&#xff1a…

走进开源企业 | 湖南大学OpenHarmony技术实训活动在开鸿智谷顺利举办!

6月24日-6月26日&#xff0c;2024开放原子校源行之湖南大学信息科学与工程学院师生走进开源企业实训交流活动顺利落下帷幕。湖南大学信息科学与工程学院的师生代表团一行90人参与了湖南开鸿智谷数字产业有限公司&#xff08;以下简称“开鸿智谷”&#xff09;与母公司拓维信息系…

计算机的错误计算(十八)

摘要 计算机的错误计算&#xff08;四&#xff09;指出一元二次方程的计算精度问题。本节给出其一种解决方案。 计算机的错误计算&#xff08;四&#xff09;与&#xff08;十七&#xff09;分别指出一元二次方程的求解是具有挑战性的难题&#xff0c;其出错原因是因为相减相消…

(超详细)数据结构——“队列”的深度解析

目录 前言&#xff1a; 1.队列的概念 2.队列的实现 3.代码实现队列 3.1 队列的初始化 3.2 插入 3.3 删除 3.4 队列的队头&#xff0c;队尾和大小 3.5 判空 3.6 销毁 3.7 测试 前言&#xff1a; 队列与栈都是线性表&#xff0c;它们的结构也非常类似&#…

一维信号全变分(TV)降噪方法(MATLAB)

信号降噪一直是领域研究的热点&#xff0c;这是一项十分有意义并且极具挑战性的工作&#xff0c;经过几十年来相关科研人员的共同努力&#xff0c;降噪技术得到了极大的发展&#xff0c;并在现实生活中也得到了广泛的应用。其中&#xff0c;许多常用的方法有&#xff1a;小波变…

2024 年江西省研究生数学建模竞赛题目 B题投标中的竞争策略问题--完整思路、代码结果分享(仅供学习)

招投标问题是企业运营过程中必须面对的基本问题之一。现有的招投标平台有国家级的&#xff0c;也有地方性的。在招投标过程中&#xff0c;企业需要全面了解招标公告中的相关信息&#xff0c;在遵守招投标各种规范和制度的基础上&#xff0c;选择有效的竞争策略和技巧&#xff0…

【PB案例学习笔记】-26制作一个带浮动图标的工具栏

写在前面 这是PB案例学习笔记系列文章的第26篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

Python处理excel数据详解

1.导入文件 注意&#xff1a;要把excel放到跟你的python文件在同一个地方 import pandas as pd import numpy as np dfpd.read_excel("鸢尾花训练数据.xlsx",engine"openpyxl") import pandas 先引入 (若没有下载 需要在终端下载 pip install pandas)…

【Spring Boot】基于 JPA 开发的文章管理系统(CRUD)

基于 JPA 开发的文章管理系统&#xff08;CRUD&#xff09; 1.实现文章实体2.实现数据持久层3.实现服务接口和服务接口的实现类3.1 创建服务接口3.2 编写服务接口的实现 4.实现增、删、改、查的控制层 API 功能4.1 获取文章列表4.2 根据 id 获取文章对象4.3 新增4.4 保存4.5 删…

安全隔离上网的有效途径:沙箱

在数字化浪潮日益汹涌的今天&#xff0c;网络安全成为了不可忽视的重要议题。沙箱技术作为一种高效的隔离机制&#xff0c;为企业和个人提供了一种在享受网络便利的同时&#xff0c;保障系统安全的解决方案。本文旨在深入探讨沙箱技术如何做到隔离上网&#xff0c;从而为用户提…

cube-studio 开源一站式云原生机器学习/深度学习/大模型训练推理平台介绍

全栈工程师开发手册 &#xff08;作者&#xff1a;栾鹏&#xff09; 一站式云原生机器学习平台 前言 开源地址&#xff1a;https://github.com/tencentmusic/cube-studio cube studio 腾讯开源的国内最热门的一站式机器学习mlops/大模型训练平台&#xff0c;支持多租户&…

Java的日期类常用方法

Java_Date 第一代日期类 获取当前时间 Date date new Date(); System.out.printf("当前时间" date); 格式化时间信息 SimpleDateFormat simpleDateFormat new SimpleDateFormat("yyyy-mm-dd hh:mm:ss E); System.out.printf("格式化后时间" si…

使用PHP解析和处理HTML/XML以创建Web爬虫的示例

使用PHP解析和处理HTML/XML以创建Web爬虫的示例 引言&#xff1a; Web爬虫是一种自动化工具&#xff0c;用于从万维网&#xff08;World Wide Web&#xff09;上抓取数据。PHP作为一种流行的服务器端脚本语言&#xff0c;具有丰富的库和功能&#xff0c;可以方便地解析和处理H…

Unity 功能 之 创建 【Unity Package】 Manager 自己自定义管理的包的简单整理

Unity 功能 之 创建 【Unity Package】 Manager 自己自定义管理的包的简单整理 一、简单介绍 Unity Package 是一种模块化的资源管理和分发方式&#xff0c;用于将游戏开发所需的代码、资源、配置文件等内容打包成一个独立的、可重用的组件。Unity Package 可以在多个项目之间…

深入理解 “androidx.databinding.DataBindingUtil“ 细节和使用

介绍 数据绑定&#xff08;Data Binding&#xff09;是 Android 中的一个强大功能&#xff0c;它允许你使用声明性格式而不是编程方式将布局中的 UI 组件绑定到应用中的数据源。androidx.databinding.DataBindingUtil 类是一个工具类&#xff0c;它提供了用于处理数据绑定的方…

GlimmerHMM安装与使用-生信工具24

GlimmerHMM 01 概述 GlimmerHMM是一种基于广义隐马尔科夫模型&#xff08;GHMM&#xff09;的新型基因预测工具。虽然该基因预测工具符合GHMM的总体数学框架&#xff0c;但它还结合了从GeneSplicer程序中改编的剪接位点模型。可变长度的特征状态&#xff08;例如外显子、内含…