SSM框架学习——Spring的控制反转IoC与依赖注入DI

控制反转IoC与依赖注入DI

概念

提到Spring首先想到的肯定是Spring的IoC容器了。在了解Spring的用法之前我们必须了解什么是控制反转IoC依赖注入DI

**控制反转(Inversion of Control)**是面向对象编程中的一种设计原则,它建议将不需要的职责移出类,让类专注于核心职责,从而提供松散耦合,提高优化软件程序设计。

简单一点来说,我原来需要一个对象需要自己手动去new,我必须知道哪些类实现了相应的接口,而有了控制反转,我只需要向框架的容器要一个,由它实现装配,对对象组件的控制权也就由代码转移到了外部容器。

控制反转有多种实现方式:

  • 依赖注入(Dependency Injection)
  • 依赖查找(Dependency Lookup)

其中依赖查找又可以分为依赖拖拽上下文依赖查找

依赖注入

我们这里主要来探讨依赖注入,它的基本原则是应用组件不应该负责查找资源或者其他依赖对象,配置对象的工作由IoC容器负责,即组件不做定位查询,只提供常规的Java方法让容器去决定依赖关系。

Spring实现DI有四种方式:构造器注入、setter注入、接口注入和属性注入。接口注入Spring3.x的特性,Spring4.x已经被废弃掉了,我们就着重探讨另外三者。

我们还是在原来的test1项目上进行演示。首先,我们创建一个接口,其名称ITest

我们在接口中声明一个方法void say()

package top.cairbin.test1;

public interface ITest {
	void say();
}

接下来我们定义一个实现ITest接口的类Test。这里不给出操作图片,请仿照之前的自行创建一个Test.java文件,下文同理。

package top.cairbin.test1;

public class Test implements ITest{
	@Override
	public void say() {
		System.out.println("Hi");
	}
}

我们创建一个调用者类User,它需要一个实现了ITest接口的对象。

package top.cairbin.test1;

public class User {
	private ITest test;
	
	public void testSay() {
		test.say();
	}
}

我们尝试在App中去实例化这个对象并调用void testSay()这个方法。

package top.cairbin.test1;

public class App 
{
    public static void main( String[] args )
    {
        User user = new User();
        user.testSay();
    }
}

接下来运行,发现了一堆报错。这很显然,因为我们没有给定User类中对应ITest类型的属性的实现。

我们接下来尝试使用依赖注入来解决这个报错。

先创建一个与src平级的文件夹,名称叫做resources

然后对这个文件夹右键,点击Build Path里的Use as Source Folder

我们要告诉IoC容器谁实现了ITest接口,于是我们在resources目录下创建一个AppCtx.xml文件。

在文件中写入如下内容

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	
	<bean id="test" class="top.cairbin.test1.Test"></bean>
	
</beans>

我们还要告诉Spring去加载这个xml配置文件,于是在App类中(注意新引入的两个包)

package top.cairbin.test1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App 
{
    public static void main( String[] args )
    {
    	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("AppCtx.xml");
        User user = (User)applicationContext.getBean("user");
        user.testSay();
    }
}

构造器注入

构造器注入是SpringFramework推荐的一种方式,它要求提供有参数的构造方法。

我们对类User进行改造

package top.cairbin.test1;

public class User {
	private final ITest test;
	
	public User(ITest test) {
		this.test = test;
	}
	
	public void testSay() {
		test.say();
	}
}

然后修改AppCtx.xml,告诉Spring类User构造器对应的参数

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	
	<bean id="test" class="top.cairbin.test1.Test"></bean>
	<bean id="user" class="top.cairbin.test1.User">
		<constructor-arg ref="test"></constructor-arg>
	</bean>
	
</beans>

在这个xml文件中,我们告诉Spring类User构造器所需参数类型。这里的user对应top.cairbin.test1.User,而且与Main函数中的getBean("user")参数一致。

点击运行,发现控制台能够正常输出了

Setter注入

User内容

package top.cairbin.test1;

public class User {
	private ITest test;
	
	public void setTest(ITest test) {
		this.test = test;
	}
	
	public void testSay() {
		test.say();
	}

}

AppCtx.xml内容

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	
	<bean id="test" class="top.cairbin.test1.Test"></bean>
	<bean id="user" class="top.cairbin.test1.User">
		<property name="test" ref="test"/>
	</bean>
	
</beans>

属性注入

属性注入,又或者说是字段注入,实际上并不是新的注入类型,它实际上通过注解实现,底层利用反射机制来设置值。

我们在AppCtx.xml文件中修改内容如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	
	<bean id="test" class="top.cairbin.test1.Test"></bean>
	<bean id="user" class="top.cairbin.test1.User" autowire="byName">
	</bean>
	
</beans>

然后修改User类,给属性加一个注解@Autowired并设置一个public void setTest(ITest test)方法。

package top.cairbin.test1;

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

public class User {
	@Autowired
	private ITest test;
	
	public void setTest(ITest test) {
		this.test = test;
	}

	public void testSay() {
		test.say();
	}
}

点击运行按钮我们能看到控制台能够正常输出。

属性注入与自动扫描

我们想扔掉讨厌的setter方法,并且不再写这么麻烦的XML文件,有一个好方法那就是自动扫描

我们修改AppCtx.xml里开启自动扫描。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="top.cairbin.test1" />
</beans>

注意这里的base-package属性,为你要扫描的包!!!

然后将Test类注册为Bean,实际上就添加一个@Component注解

@Component
public class Test implements ITest{
	@Override
	public void say() {
		System.out.println("Hi");
	}
}

同理,在User类上也添加一个@Component注解,在需要注入的字段上添加@Autowired注解

package top.cairbin.test1;

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

@Component
public class User {
	@Autowired
	private ITest test;

	public void testSay() {
		test.say();
	}
}

保存后,点击运行就能看到控制台输出。

这里对@Component注解进行说明,它就相当于我们在AppCtx.xml里添加了一个<bean></bean>标签,其id为首字母小写的类名,例如类名为TestDi,则对应id就是testDi

如果你想要自定义这个id,只需要这样写注解即可@Component("testDi")

属性注入与其它注入混合使用

问题来了,当属性注入和其它注入方式混合使用会怎么样。

在Spring4.3之前,需要添加@Autowired注解在构造函数上;在Spring4.3之后,如果只存在一个构造函数,则不用添加@Autowired,如果存在多个构造函数,则必须指定哪个来注入以来项,即在上面添加@Autowired

当属性注入与Setter注入同时使用时,例如下方代码:

public class Example {

    @Autowired
    private Bean1 bean1;
    
    @Autowired
    public void setBean1(Bean1 bean1) {
        this.bean1 = bean1;
    }  
}

Spring会优先使用Setter注入!!!

上述只是举例,在实际项目编写不要使用混合的注入方式,因为这会降低代码可读性!!

对比几种DI的方式

构造器注入

对于构造器注入,类的依赖关系在构造器中很明显,所有的依赖项在构造方法中,所以所有的依赖项都第一时间被注入到类中,且无法更改,即构造的对象是不可变的。

为什么Spring推荐这种方式?因为它可以使代码更健壮,可以防止空指针异常。

但是构造器注入也并不完美,它缺乏灵活性,不可能更改对象的依赖关系,在重构代码的时候比较麻烦。甚至有可能产生循环依赖。

Setter注入

Setter注入是一种灵活的方式,但是在多线程环境中可能变得不安全。另外Setter注入需要进行Null检查,否则可能报错,这影响了代码的健壮性。

属性注入

快速方便,与IoC容器耦合,但会带来额外的性能开销和兼容问题,同时也打破了封装这一特性,不利于面向对象编程。同时它也可能存在空指针异常,不利于代码的健壮性。

结束

本文到此结束,看完这一章你对依赖注入应该有了一个大致的了解,但是也应该会有很多疑问。Bean是什么?注解到底帮助我们实现了什么?我们将在下一节来探究这个问题。

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

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

相关文章

突破数据障碍—如何使用IP代理服务获取量子科学研究领域最新数据

写在前面 在这个数字化的时代&#xff0c;人们越来越关注隐私保护和网络访问自由。我最近也深入研究了一下IP代理服务&#xff0c;在规避地理限制、绕过封锁以及保护个人隐私方面&#xff0c;它确实发挥了关键作用。 一、基础介绍 起因是有个项目需要对量子领域进行深入的研究之…

使用C++调用讯飞星火API的详细指南

正文&#xff1a; 科大讯飞是中国领先的人工智能公司&#xff0c;其讯飞星火API为开发者提供了丰富的接口和服务&#xff0c;支持各种语音和语言技术的应用。下面是使用C接入讯飞星火API的步骤和代码示例。 步骤一&#xff1a;注册账号并创建应用 首先&#xff0c;您需要访问科…

Open3D(C++) 彩色点云RGB转灰度并显示

目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、原理概述 不同要素之间的灰度差异较为明显。点云灰度值与RGB属性的关系为:

CSRF漏洞详解与挖掘

CSRF漏洞详解与挖掘 CSRF的定义&#xff1a; CSRF&#xff0c;全称Cross-site request forgery&#xff0c;翻译过来就是跨站请求伪造&#xff0c;是指利用受害者尚未失效的身份认证信息&#xff08;cookie、会话等&#xff09;&#xff0c;诱骗其点击恶意链接或者访问包含攻…

SAD法(附python实现)和Siamese神经网络计算图像的视差图

1 视差图 视差图&#xff1a;以左视图视差图为例&#xff0c;在像素位置p的视差值等于该像素在右图上的匹配点的列坐标减去其在左图上的列坐标 视差图和深度图&#xff1a; z f b d z \frac{fb}{d} zdfb​ 其中 d d d 是视差&#xff0c; f f f 是焦距&#xff0c; b b…

mysql语句学习

SQL Select语句完整的执行顺序&#xff1a; 1、from子句组装来自不同数据源的数据&#xff1b; &#xff08;先join在on&#xff09; 2、where子句基于指定的条件对记录行进行筛选&#xff1b; 3、group by子句将数据划分为多个分组&#xff1b; 4、使用聚集函数进行计算&a…

【Entity Framework】EF日志-简单日志记录

【Entity Framework】EF日志-简单日志记录 文章目录 【Entity Framework】EF日志-简单日志记录一、概述二、EF日志分类三、简单的日志记录3.1 配置3.2 日志记录到控制台3.3 记录到凋试窗口3.4 记录到文件3.5 敏感数据处理3.6 详细查询异常3.6 日志级别3.7 消息内容和格式设置 一…

蓝牙耳机推荐哪个品牌好?2024火爆机型推荐,拒绝云测

​音乐和有声读物是许多人放松身心、缓解等待无聊时刻的好伴侣。尽管市面上蓝牙耳机琳琅满目&#xff0c;挑选合适的款式却颇具挑战。作为一个经验丰富的耳机用户&#xff0c;我深知哪些蓝牙耳机值得你的信赖。接下来&#xff0c;我将分享几款我个人认为很不错的蓝牙耳机来给大…

便宜的猫粮给猫吃有什么副作用?

便宜的猫粮&#xff0c;虽然价格诱人&#xff0c;但便宜的猫粮可能会给猫咪的健康带来一些隐患哦。让我们一起来了解一下&#xff0c;便宜的猫粮给猫吃会有什么副作用吧。 1️⃣ 原材料作假&#xff1a;便宜&#xff1d;低质&#xff0c;这是恒古不变的道理&#xff0c;没有那…

HTMLCSS

前端入门 1、HTML&CSS 1、选择器 通配选择器 元素选择器 类选择器 id选择器 复合(组合) 选择器 交集选择器(且) <style> p.class {... } /* 元素选择器需在前面 */.class1.class2 {... } </style>并集选择器(或者) <style> .class1, .class2, …

性能监控工具--sysstat使用

一、sysstat安装 sysstat提供了Linux性能监控工具集&#xff0c;包括sar、sadf、mpstat、iostat、pidstat等&#xff0c;用于监控Linux系统性能和使用情况。 其中sar功能非常强大&#xff0c;能够收集、报告、保存系统活动信息&#xff1a;CPU、内存、磁盘、中断、网络接口…

蓝桥杯刷题第八天(dp专题)

这道题有点像小学奥数题&#xff0c;解题的关键主要是&#xff1a; 有2种走法固走到第i级阶梯&#xff0c;可以通过计算走到第i-1级和第i-2级的走法和&#xff0c;可以初始化走到第1级楼梯和走到第2级楼梯。分别为f[1]1;f[2]1(11)1(2)2.然后就可以循环遍历到后面的状态。 f[i…

ubuntu16如何使用高版本cmake

1.引言 最近在尝试ubuntu16.04下编译开源项目vsome&#xff0c;发现使用apt命令默认安装cmake的的版本太低。如下 最终得知&#xff0c;ubuntu16默认安装确实只能到3.5.1。解决办法只能是源码安装更高版本。 2.源码下载3.20 //定位到opt目录 cd /opt 下载 wget https://cmak…

Aurora8b10b(2)上板验证

文章目录 前言一、AXI_Stream数据产生模块二、上板效果总结 前言 上一篇内容我们已经详细介绍了基于aurora8b10b IP核的设计&#xff0c;本文将基于此进一步完善并且进行上板验证。 设计思路及代码思路参考FPGA奇哥系列网课 一、AXI_Stream数据产生模块 AXIS协议是非常简单的…

【御控物联】JSON结构数据转换在物流调度系统中的应用(场景案例三)

文章目录 一、前言二、场景概述三、解决方案四、在线转换工具五、技术资料 一、前言 物流调度是每个生产厂区必不可少的一个环节&#xff0c;主要包括线边物流和智能仓储。线边物流是指将物料定时、定点、定量配送到生产作业一线的环节&#xff0c;其包括从集中仓库到线边仓、…

14种建模语言(UML)图形

前言 UML 中有四种关系&#xff1a;依赖、关联、泛化和实现。这四种关系是 UML 模型中可以包含的基本关系事物。这里介绍14种UML图形:类图&#xff0c;对象图&#xff0c;包图&#xff0c;构件图&#xff0c;组合结构图&#xff0c;部署图&#xff0c;制品图&#xff0c;用例图…

【Web理论篇】Web应用程序安全与风险

目录 &#x1f332;1.Web应用程序的发展历程 &#x1f342;1.1 Web应用程序的常见功能&#x1f342;1.2 Web应用程序的优点 &#x1f332;2.Web安全 &#x1f342;2.1Web应用程序常见漏洞&#x1f342;2.2未对用户输入做过滤&#x1f342;2.3 造成这些漏洞的原因是什么呢&…

数据安全之认识数据库防火墙

文章目录 一、什么是数据库防火墙二、数据库防火墙的主要功能三、数据库防火墙的工作原理四、数据库防火墙如何防护数据库免受SQL注入攻击五、数据库防火墙的部署方式六、数据库防火墙与网络防火墙的关系与区别七、数据库防火墙的应用场景 随着信息技术的快速发展&#xff0c;数…

数据结构进阶篇 之【选择排序】详细讲解(选择排序,堆排序)

民以食为天&#xff0c;我以乐为先 嘴上来的嘘寒问暖&#xff0c;不如直接打笔巨款 一、选择排序 1.直接选择排序 SelectSort 1.1 基本思想 1.2 实现原理 1.3 代码实现 1.4 直接选择排序的特性总结 2.堆排序 HeapSort 跳转链接&#xff1a;数据结构 之 堆的应用 二、完…

C++ | Leetcode C++题解之第7题整数反转

题目&#xff1a; 题解&#xff1a; class Solution { public:int reverse(int x) {int rev 0;while (x ! 0) {if (rev < INT_MIN / 10 || rev > INT_MAX / 10) {return 0;}int digit x % 10;x / 10;rev rev * 10 digit;}return rev;} };