Spring IoCDI(下)—DI的尾声

        我们之前学习了控制反转IoC,接下来就开始学习依赖注入DI的细节。

        依赖注入是一个过程,是指IoC容器在创建Bean时,去提供运行时所依赖的资源,而资源指的就是对象。我们使用 @Autowired 注解,完成依赖注入的操作。简单来说,就是把对象取出来,放到某个类的属性中。由此,依赖注入也被称之为 “对象注入”、“属性装配”,具体含义需要结合文章的上下文来理解。

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

1、属性注入(Field Injection)

2、构造方法注入(Construct Injection)

3、Setter 注入(Setter Injection)

1. 属性注入

        属性注入是使用 @Autowired 实现的,将UserService 类注入到UserController类中,UserService 类代码如下:

package com.example.zxslzw2014_8_11;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void doService() {
        System.out.println("do Service...");
    }
}

         UserController类的实现代码如下:

package com.example.zxslzw2014_8_11;

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

@Controller
public class UserController1 {
    //注入方法1:属性注入
    @Autowired
    private UserService userService;
    public void sayHi() {
        userService.doService();
        System.out.println("hi, UserController");
    }
}

        启动类获取到UserController的doService方法,代码如下:

package com.example.zxslzw2014_8_11;


import com.example.zxslzw2014_8_11.controller.UserController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;


@SpringBootApplication
public class Zxslzw2014811Application {

    public static void main(String[] args) {
        //获取Spring上下文对象
        ApplicationContext context = SpringApplication.run(Zxslzw2014811Application.class, args);
        //从Spring上下文中获取对象
        UserController1 userController1 = (UserController1) context.getBean("userController1");
        //使用对象
        userController1.sayHi();


    }
}


        运行结果如下:

        去掉注解@Autowired,运行结果如下:

         报错信息显示空指针异常,没办法调用doService() 方法,因为userServer为空。没有加@Autowired注解,即没有注入依赖,Spring拿不到这个属性,就不会给它初始化了,那么它肯定就是一个空指针了。 

2. 构造方法注入

        构造方法注入就是在类的构造方法中实现注入,代码如下:

package com.example.zxslzw2014_8_11;

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

@Controller
public class UserController1 {
    private UserService userService;
    //注入方法2:构造方法注入
    @Autowired
    public UserController1(UserService userService) {
        this.userService = userService;
    }
    public void doController() {
        userService.doService();
        System.out.println("hi, UserController");
    }
}

package com.example.zxslzw2014_8_11;

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

@Controller
public class UserController1 {
    private UserService userService;
    //注入方法2:构造方法注入
    public UserController1(UserService userService) {
        this.userService = userService;
    }
    public void doController() {
        userService.doService();
        System.out.println("hi, UserController");
    }
}

        运行结果如下:

 

       如果类只有一个构造方法,那么@Autowired注解可以省略;但如果类有多个构造方法,那么就需要添加上@Autowired来明确指定要使用哪个构造方法了。下面给userController1增加一个无参构造,代码如下:

package com.example.zxslzw2014_8_11;

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

@Controller
public class UserController1 {
    //注入方法1:属性注入
//    @Autowired
    private UserService userService;
    //注入方法2:构造方法注入
//    @Autowired
    public UserController1(){
        
    }
    public UserController1(UserService userService) {
        this.userService = userService;
    }
    public void doController() {
        userService.doService();
        System.out.println("hi, UserController");
    }
}

        运行结果如下:

        报错显示,空指针异常,我们的类交给Spring管理,Spring内部会给我们自动创建对象,但是是通过构造函数创建的,上图我们写了两个构造函数,如果不加@Autowired注解,Spring默认使用无参构造函数,如此就不能成功创建对象了,所以这个userService也自然是空指针了。

        现在代码改一下,把无参构造函数注释掉,更新构造函数,代码如下:

package com.example.zxslzw2014_8_11;

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

@Controller
public class UserController1 {
    //注入方法1:属性注入
//    @Autowired
    private UserService userService;
    private UserComponent userComponent;
    //注入方法2:构造方法注入
    public UserController1(UserService userService) {
        this.userService = userService;
    }
    public UserController1(UserService userService, UserComponent userComponent) {
        this.userService = userService;
        this.userComponent = userComponent;
    }
    public void doController() {
        userService.doService();
        userComponent.doComponent();
        System.out.println("hi, UserController");
    }
}

        运行结果如下:

          报错显示,没有找到默认的构造方法,因为这里出现了两个构造方法,Spring不知道该用哪个,现在给第二个构造方法加上@Autowired注解,表示让Spring使用被注解的构造方法,运行结果如下:

        综上:
1、只有一个构造函数的情况,可以不加@Autowired

2、如果有多个构造函数,需要指定默认的构造函数(通过@Autowired指定,如果未指定,默认使用无参的构造函数)

        构造规范:如果添加构造函数,把无参构造函数显示添加(也就是把构造函数写下来,再给注释掉)

3. Setter注入

        Setter注入和属性的Setter方法实现类似,只不过在set方法的时候需要加上@Autowired注解,代码如下:

package com.example.zxslzw2014_8_11;

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

@Controller
public class UserController1 {
    private UserService userService;
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;

    }
    public void doController() {
        userService.doService();
        System.out.println("hi, UserController");
    }
}

        结果如下:

 

         同时我们把@Autowired注解去掉的话,又会出现空指针异常,原因和属性注入把@Autowired的情况一样,就是spring优先使用空参构造,结果空参构造的对象不能匹配到我们所调用的方法。

4. 三种注入的优缺点分析

4.1 属性注入

优点:
        1、简洁、使用方便。

缺点:
        1、只能用于IoC容器,如果非IoC容器则不可用,并且只有在使用的时候才会回出现NPE(空指针异常)。

         reason:如下图,可以看到,它的来源是Spring的,那么就只能用于IoC容器了。

        2、不能注入一个final修饰的属性。

        reason: final修饰的属性有个特点,必须初始化,如果我们给属性加上final,会有两种解决方案:

        方案1、提供构造函数,如图:

         如果加上构造方法,我们的属性注入就变成了构造方法注入。

        方案二: 给它初始化,new 一个对象:

         如此我们的代码就只能自己管理了,Spring不会帮我们管理,这不是ioc的思想;

 4.2 构造方法注入

        (Spring4.X推荐)

        SpringBoot和Spring的版本号对应:

Spring Boot3.X -> Spring 6

Spring Boot2.X -> Spring 4

优点:
        1、可以注入final修饰的属性。

        final修饰的属性要初始化,构造方法会进行初始化,复合它的要求。

        2、注入的对象不会被修改。

        因为构造方法在这个类创建的时候就会给它进行赋值了,不会再对它进行修改

        3、依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法。

        在类加载的这个阶段,就会执行构造方法了,把依赖对象给初始化完成

        4、通用性好,构造方法是JDK支持的,所以更换任何框架,它都是适用的。

        因构造方法是JDK支持的,不再Spring框架也能正常的使用

缺点:
        注入多个对象时,代码会比较繁琐。

4.3 Setter注入

        (Spring3.X推荐)
优点:
        方便在类实例之后,重新对该对象进行配置或注入。

        因为Setter方法是可以被其他地方调用的,所以即使类已经被实例化了,也可以重新对该对象进行配置或注入。

缺点:
        1、不能注入一个final修饰的属性。

        因为可能会被多次修改,所以不能使用final修饰。

        2、注入对象可能会被改变,因为Setter方法可能会被多次调用,就有被修改的风险。

        Setter方法当然能被修改了,这即使它的优点,也是它的缺点。

4.4 Autowired查找依赖顺序

        1、根据名称和类型去查。

        2、如果根据名称查不到,就会根据类型去查。

        根据名称查不到了,去查找类型,这时如果类型匹配多个,就会报错

5. @Autowired存在问题

        当同一类型存在多个bean时,使用@Autowired会存在问题。代码如下:

@Component
public class BeanConfig {
    @Bean
    public UserInfo userInfo1() {
        UserInfo user = new UserInfo();
        user.setId(6);
        user.setName("shenmengyao");
        user.setAge(18);
        return user;
    }
 
    @Bean
    public UserInfo userInfo2() {
        UserInfo user = new UserInfo();
        user.setId(7);
        user.setName("yuanyiqi");
        user.setAge(19);
        return user;
    }
}

        此时我们在UserController1类里面注入UserInfo类,代码如下:(下面这几个的注入方式都是错误的)

5.1 引入Autowired的错误代码:

5.1.1 属性注入:

        尝试运行出现如下结果: 

5.1.2 构造方法注入 

5.1.3 Setter方法注入 

5.1.4 启动类代码:

        上面这三种方式注入都会出问题,启动程序后,而报错信息也都是一样的,如上图所示:

        程序还没启动就失败了,可以看出来,Spring的依赖注入是在项目启动前就开始注入的了。

        上面报错提示:UserController1类需要一个bean,但是有两个,下面也打印出是哪两个bean了,Action介绍的就是解决方案。报错日志非常详细。

        报错信息说UserController1类找不到依赖注入的是哪一个,因为有多个方法被@bean注释,而依赖注入时,三个方法的属性名都是userInfo,系统先根据userInfo名称查找,但BeanConfig类没有这个方法名,那就只能去根据类名找了,但有2个bean,Spring就不知道要找那个了,并不是@bean注释下的方法名(userInfo1 / userInfo2),Spring并不知道该注入哪个依赖,所以报错了。

        在项目启动失败,可以把Filed看为属性,如上图:这个是使用属性注入的,会有Field

         构造方法和Setter注入都是第一张报错图,但就不是Field了,而是Parameter,但其实三种注入的报错原因都是一样的。

        解决方案:使用属性注入时,就把属性名改成bean修饰的其中之一的方法名就好了;使用@Parimary注解;使用@Qualifier注解;使用@Resource注解。

5.2 解决方案

5.2.1 解决方案一:根据名称去查

        属性名改成bean修饰的其中之一的方法名

1、属性注入:

2、构造方法注入: 

3、Setter方法注入:

        上面三种执行结果都一样,这里虽然注入了依赖,但没有用这些依赖;

5.2.1 解决方案二:

        给想要拿到的对象加上@Primary注解

        这个可以理解为依赖注入后,有多个依赖的方法,但默认使用加了@Primary的方法,代码如下:

1、UserController类

2、BeanConfig类:

代码运行结果:

         其他注入的方式,使用@Primary注解用法也一样,把想要拿到的对象加上@Primary注解就好了。

5.2.3 解决方案三:

        加@Qualifier注解,指定引入的依赖对象

UserController类:

        BeanConfig类和启动类与最初的代码一样,不用变。代码最终能够成功运行,结果和之前类似;

5.2.4 解决方案四:加@Resource注解

        这里和上面的三方案代码改变的只有UserController类,其他都不变,UserController类的代码如下:

@Controller
public class UserController {
    @Resource(name = "userInfo1")
    @Autowired
    private UserInfo userInfo;
        
    public void sayHi() {
        System.out.println(userInfo.toString());
        System.out.println("hello, controller");
    }
}

        运行结果如下:

         这个注解不是Spring的,而是JDK本身自带的,JDK早期也有这样的注解,所以Spring不推荐使用这个注解,因为不是自己开发的,如果出现啥问题,不好处理,是有着不可控因素的原因;还有使用自家的东西也肯定会更放心一些。

5.3 @Autowired 与 @Resource 的区别

1、@Autowired 是 Spring框架提供的注解,而@Resource是JDK提供的注解。

2、@Autowired默认是按照类型注入,而@Resource是按照名称注入。相比于 @Autowired 来说,@Resource 支持更多的参数设置;例如 name 设置,根据名称获取 Bean。

6. Spring IoC&DI 的总结

1、Spring,Spring Boot 和 Spring MVC的关系以及区别
(1)、Spring
        简单来说,Spring是一个开发应用框架,其目的是用于简化企业级应用程序开发。

        Spring的主要功能:管理对象,以及对象之间的依赖关系,面向切面编程、数据库事务管理、数据访问、web框架支撑等等。

        Spring具备高度可开发性,并不强制依赖Spring,开发者可以自由选择Spring的部分或者全部,Spring可以无缝继承第三方框架,比如数据访问框架(Hibernate、JPA等等),web框架(如:Struts、JSF等等)。

(2)、Spring MVC
        Spring MVC是Spring的一个子框架,Spring诞生之后,大家按照MVC模式设计了一个MVC框架(用Spring解耦),主要用于开发WEB应用和网络接口,所以Spring MVC是一个Web框架。

        Spring MVC是基于Spring进行开发的,可以让我们更简洁的进行Web层开发,支持灵活的URL到页面控制器的映射,提供了强大的约定大于配置的契约式编程支持,非常容易与其他视图框架集成,如 Velocity、FreeMarker等等。

(3)、Spring Boot
        Spring Boot 是对Spring的一个封装,为了简化Spring一样的开发而出现的,使用Spring Boot 可以更加快速的搭建框架,降低开发成本,让开发人员更加专注于Spring应用的开发,而无需过多关注XML的配置和一些底层的实现。

        Spring Boot可以快速的集成其他框架进来。想使用Spring Boot开发Web项目,只需要引入Spring MVC框架即可,Web开发的工作是Spring MVC完成的,而不是Spring Boot,想完成数据访问,只需要引入Mybatis框架即可。

        Spring Boot只是辅助简化项目开发的,让开发变得更加简单,甚至不需要额外的web服务器,直接生成jar包执行即可。

(4)、总结
        Spring MVC和Spring Boot都属于Spring,Spring MVC是基于Spring的一个MVC框架,而Spring Boot是基于Spring的一套快速开发整合包。

        之前写的图书管理系统代码中,整体框架是通过SpringBoot搭建的IoC,DI功能是Spring提供的,而Web相关功能是Spring MVC提供的。

        因为这三个专注的领域不同,所以解决的问题也不一样,总的来说,Spring就像一个大家族,有众多衍生产品,但它们的基础都是Spring;

2、bean的命名

(1)、五大注解存储的bean
1、类名前面两位字母均为大写,则bean名称为该类名本身(特殊情况)。

2、不是上面的特殊情况,其他的类名,首字母小写,驼峰形式命名。

3、通过 value 属性设置bean名 ,例如:@Controller (value = "user")。

(2)、@Bean注解存储的bean

1、bean名称为方法名。

2、通过name属性设置bean名,例如:@Bean (name = {"u1", "user1"})。

ps:本次的内容就到这里了,如果对你有所帮助的话,就请一键三连哦!!!

本文的封面来自:bilibili苏杉杉的pv,侵权删 url:https://www.bilibili.com/video/BV1vo4y167eh/?spm_id_from=333.999.0.0&vd_source=866da5be2ef0ddd213b053523da53138
————————————————

电子签名:上嘉路

 

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

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

相关文章

【数据结构初阶】二叉树--基本概念

hello! 目录 一、树 1.1 树的概念和结构 1.2 树的相关术语 1.3 树的表示 1.4 树形结构实际应用场景 二、二叉树 2.1 概念和结构 2.2 特殊的二叉树 2.2.1 满二叉树 2.2.2 完全二叉树 2.3 二叉树的存储结构 2.3.1 顺序结构 2.3.2 链式结构 …

keil调试程序进入“BEAB BKPT 0xAB“断点处

1:异常现象 发现程序新增加代码的时候,程序会进入 “BEAB BKPT 0xAB” 断点处,无法进入main函数; 2:异常原因 屏蔽新增加的代码,最后发现是复制过来的代码中有 printf() 函数打印日志,但是k…

Windows 环境下 Go 语言使用第三方压缩包 gozstd 的报错处理

该文章主要记录在windows平台用go语言使用gozstd包时,遇到的错误及处理过程(踩坑之旅)! 一、gozstd简介 gozstd是一个针对Zstandard(简称Zstd)的Go语言包装器,它提供了简单且高效的API&#xf…

赋能基层,融合创新:EasyCVR视频汇聚平台构建平安城市视频共享系统

一、雪亮工程建设的意义 雪亮工程的核心在于通过高清视频监控、环境监测和智能预警等先进技术手段,构建一个高效、智能、安全、便捷的社会安全防控体系。这一工程的建设不仅代表了现代化科技手段在城市治安管理中的应用,更是提升社会安全保障能力、推动…

【Angular18】封装自定义组件

1. 准备组件 2. 创建打包文件夹及部分配置文件 创建 文件夹app-legalentities-root拷贝组件源文件到新的文件夹app-legalentities中创建文件 .npmrc registry发布地址always-authtrue创建文件 ng-package.json {"$schema": "./node_modules/ng-packagr/ng-pac…

自动化解决 reCAPTCHA v2:CapSolver 教程

对于那些经常进行网页爬取的人来说,你是否曾觉得 reCAPTCHA v2 就像是互联网版的过于严格的裁判员,总是在质疑你的真实性?但如果你能够轻松且合规地与这些裁判员达成和解,使你的网络搜索和自动化任务变得更顺畅,那该有…

社交媒体分析:如何利用Facebook的数据提升业务决

在数字化时代,社交媒体已经成为企业战略中不可或缺的一部分。Facebook,作为全球最大的社交平台之一,提供了丰富的数据资源,这些数据不仅能够帮助企业了解市场趋势,还能提升业务决策的精准度。本文将探讨如何有效利用Fa…

共享经济背景下校园、办公闲置物品交易平台-计算机毕设Java|springboot实战项目

🍊作者:计算机毕设匠心工作室 🍊简介:毕业后就一直专业从事计算机软件程序开发,至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长:按照需求定制化开发项目…

navicate premium16破解

下载链接:https://pan.baidu.com/s/1BWowOJLYchFcRMgIn-j97A?pwdvmfu 双击安装navicat160_premium_cs_x64.exe,安装完不要打开 然后断网打开NavicatCracker.exe 打开如果报病毒按照下面方法处理: 记得一定要断网,不断网…

安卓相关环境配置

安卓相关环境配置 偶尔更新。。。 JEB(动态调试好用) JEB动态调试Smali-真机/模拟器(详细,新手必看) 夜步城 JADX官网(静态分析) https://github.com/skylot/jadx/releases/tag/v1.5.0 雷…

嵌入式软件--模电基础 DAY 2

强电和弱电,简单一点是以电死人为标准的,交流电36伏特以下,直流电24V以下,为安全电压,是为弱电,反则强电。 市电进入家庭,连接你的电脑,220V的电压为什么没有让你感到危险&#xff…

怎么屏蔽电脑监控软件?企业管理者的智慧选择——精准定位,合理屏蔽,让监控软件成为助力而非障碍!

电脑监控软件在企业管理中扮演着日益重要的角色,它们能够提升工作效率、保障信息安全、预防内部风险。然而,过度或不当使用监控软件也可能引发员工隐私担忧,影响工作积极性和团队氛围。因此,作为企业管理者,如何精准定…

论文创新大杀器!LSTM结合UNet,性能突出,涨点显著

最近,浙大等团队提出了xLSTM-UNet,通过将U-Mamba中的Mamba换成xLSTM,就可以直接提升2D和3D医学图像分割性能,涨点效果显著! xLSTM-UNet是一种结合了LSTM和UNet的混合网络模型,这类模型保留了UNet出色的空间…

迭代器失效

一、什么是迭代器失效 迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指…

数据埋点系列 17| 预测分析和预测模型:用数据洞察未来

在数据驱动的决策时代,预测分析和预测模型已成为组织的重要战略工具。通过分析历史数据,我们可以预测未来趋势,做出更明智的决策。本文将深入探讨预测分析的核心概念、常用技术和实际应用。 目录 1. 预测分析的基础1.1 预测分析的类型 2. 高…

Unity与UE,哪种游戏引擎适合你?

PlayStation vs Xbox,Mario vs Sonic,Unreal vs Unity?无论是游戏主机、角色还是游戏引擎,人们总是热衷于捍卫他们在游戏行业中的偏爱。 专注于游戏引擎,Unity和Unreal Engine(简称UE4)是目前市…

C++:平衡二叉搜索树之红黑树

一、红黑树的概念 红黑树, 和AVL都是二叉搜索树, 红黑树通过在每个节点上增加一个储存位表示节点的颜色, 可以是RED或者BLACK, 通过任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树能够确保没有一条路径会比…

C++ 11相关新特性(lambda表达式与function包装器)

目录 lambda表达式 引入 lambda表达式介绍 lambda表达式捕捉列表的传递形式 lambda表达式的原理 包装器 包装器的基本使用 包装器与重载函数 包装器的使用 绑定 C 11 新特性 lambda表达式 引入 在C 98中,对于sort函数来说,如果需要根据不同的比较方式实现…

超网和无类间路由是什么?

​一、超网概述 超网是将多个连续的网络地址组合成一个增加的网络地址的技术。常用于减少路由器的路由表大小,网络的可扩展性。通过合并连续的子网,超网可以减少路由入侵的数量,从而提高网络的效率。 超网的实现基于合并多个具有连续IP地址…

【vue教程】五. Vue 的路由管理

目录 往期列表本章涵盖知识点回顾Vue Router 的基本概念什么是 Vue Router?为什么需要 Vue Router? 路由的配置和使用安装 Vue Router创建路由在 Vue 实例中使用路由模板中的路由链接 动态路由和嵌套路由动态路由嵌套路由 路由守卫什么是路由守卫&#x…