Spring入门——IoC控制反转

前言

本博客是博主用于学习Spring的博客,如果疏忽出现错误,还望各位指正。

Bean

Bean的概念

Bean的详解,可以参考这篇文章。

【SpringBoot】Bean 是什么?_sptingboot bean 是什么-CSDN博客

Bean 作为 Spring框架面试中不可或缺的概念,其本质上是指代任何被 Spring 加载生成出来的对象。(本质上区别于 Java Bean,java Bean 是对于 Java 类的一种规范定义)

Spring Bean 代表着 Spring 中最小的执行单位,其加载、作用域、生命周期的管理都由 Spring 操作。可见 Spring Bean 在整个 Spring 框架中的重要地位。

我们为了便于理解IoC思想,可以将IOC容器管理的Java对象称为Spring Bean,认为与使用new创建的对象无任何区别。

Bean的设计目的

在了解 Spring 是如何管理 Bean 组件之前,有必要了解为什么 Spring 需要设计出来这么一套机制。假设咱们是某个大家族里的公子,家里有一位无微不至的大管家,无论你需要什么,只要跟管家说一下,他就能给你找来。
有一天,你突然想吃帝王蟹,就让管家去搞,管家听到命令后,很快啊!给你搞来了……

至于管家到底是抓来的、还是买来的,作为少爷的你自然是不关注的。

与此相类似的,如果把程序员想象成少爷,那么 Spring就是我们忠诚的管家先生。当我们需要用容器内的对象时,只需要“告诉” Spring,Spring 就能自动帮我们加载,我们则无需考虑这个 Bean 到底是如何加载的、什么时候回收等细节逻辑。我们只需要使用即可。由此一来,降低了使用门槛,也减少了对于细节的一些管理。

控制反转(Inversion of Control,缩写为IoC)

引入实例

在介绍IoC思想前我们首先来看一个例子,参考来源06.入门-入门案例实现步骤_哔哩哔哩_bilibili

一般,作为Java初学者的我们,在调用一个类中的方法时,一般都要手动new一个类,然后去调用那个方法,然而,Spring为我们提供了一种不用手动new的方式,去调用这个方法。

首先我们根据Spring的规定要求,配置pom.xml文件。

之后我们正常定义一个User类,包含add()方法。

之后我们按照Spring规范在资源文件夹中创建.xml文件并进行配置,完成Bean的定义信息。

进行最终测试,此时我们就可以在控制台看到add方法被调用,而我们并没手动new个User对象。

那么这个被Spring创建的对象是如何返回到我们这个测试类中的呢?

Spring Bean返回流程

基本流程就是IoC容器获取.xml的配置文件中Bean信息

之后抽象,BeanDefinitionReader,针对不同方式的加载配置文件,加载到IOC容器里

IOC得到Bean的定义信息后进行实例化,BeanFactory工厂+反射机制,getBean获取最终对象。

经过这个实例,我们差不多可以清楚Spring如何通过IoC容器创建对象,从而不需要手动new一个对象。那么接下来我们正式介绍一下IoC

IoC思想

控制反转(IoC)是一种编程思想,旨在将组件间的依赖关系从硬编码中解耦出来,交由外部容器或框架进行管理。 容器的概念:比如水和杯子,书和书包…… Spring通过IoC容器管理所有Java对象的实例化和初始化,控制对象与对象之间的依赖关系。IoC容器是Spring框架中最重要的核心组件之一,贯穿了Spring从诞生到成长的过程。

控制反转,反转的是什么?

将对象创建的权利交出去,交给Ioc容器负责。

将对象和对象之间关系的维护权交出去,交给Ioc容器负责。

容器放的Bean对象,使用Map集合(id,Bean)

依赖注入

依赖注入(DI)是控制反转的一种实现方式,通过在运行时动态地将依赖对象注入到被依赖对象中,实现对象之间的解耦。 比如User中有个Person类,到时候创建时候,顺带也把它根据.xml建好了。这样,我们就能极大地降低耦合度。

当 User 类依赖于 Person 类时,如果直接在 User 类中创建 Person 类的实例,那么它们之间的耦合度就比较高。为了降低耦合度,可以使用 IoC 容器来管理 Person 类的实例,并通过依赖注入的方式将其注入到 User 类中。

让我们通过一个具体的例子来说明:

假设有一个 User 类,它依赖于 Person 类:

public class User {private Person person;public User() {this.person = new Person();}public void greet() {System.out.println("Hello, " + person.getName());}
}

在这个例子中,User 类直接在构造函数中创建了 Person 类的实例,导致了 User 类与 Person 类之间的耦合度较高。

现在,我们可以通过 IoC 容器和依赖注入来降低耦合度。假设我们使用 Spring 框架作为 IoC 容器,那么可以这样修改代码:

首先,定义 Person 类:

public class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}
}

然后,修改 User 类,使用依赖注入:

public class User {private Person person;public User(Person person) {this.person = person;}public void greet() {System.out.println("Hello, " + person.getName());}
}

接下来,在 Spring 配置文件中配置 Bean:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="person" class="com.example.Person"><constructor-arg value="John Doe" /></bean><bean id="user" class="com.example.User"><constructor-arg ref="person" /></bean></beans>

现在,Person 类的实例由 Spring 容器管理,而不是由 User 类直接创建。User 类在构造函数中接收一个 Person 类的实例,这就是依赖注入。这样一来,User 类和 Person 类之间的耦合度降低了,同时也提高了代码的灵活性和可维护性。

当你更改了 Person 类的实现方式时,只需要修改配置文件中的 Person Bean 的定义,而不需要修改 User 类的代码。User 类仍然通过依赖注入接收 Person 类的实例,并且不需要关心 Person 类的具体实现细节。

例如,如果你要修改 Person 类的构造函数,或者添加新的属性或方法,只需修改 Person 类本身,而不需要修改 User 类的代码。然后,你只需更新 Spring 配置文件中 Person Bean 的定义,以反映出 Person 类的更改。

这种解耦的方式使得代码更加灵活和可维护,因为不同组件之间的依赖关系被管理在配置中,而不是硬编码在代码中。这样一来,当需要进行修改或者扩展时,只需修改相应的组件,而不会对整个系统造成影响。

假设在 Person 类中添加了一个新的属性 age,并且需要在构造函数中初始化它。这是修改后的 Person 类的代码:

public class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}
}

现在,我们需要更新 Spring 配置文件中 Person Bean 的定义,以便在创建 Person 实例时提供 age 参数。假设我们现在希望每个 Person 对象的年龄都是 30,我们可以这样更新配置文件:

<bean id="person" class="com.example.Person"><constructor-arg value="John Doe" /><constructor-arg value="30" />
</bean>

在这个例子中,我们只需更新了 Spring 配置文件中 Person Bean 的定义,为构造函数提供了一个额外的参数值(这个参数值也可以是动态地根据数据库来传递)。而不需要修改 User 类的代码。User 类仍然通过依赖注入接收 Person 类的实例,并且不需要关心 Person 类的具体实现细节。

这种方式使得当我们修改了 Person 类的实现方式时,对于依赖于 Person 类的其他组件(比如 User 类),几乎没有影响。这样一来,我们可以更容易地扩展和维护代码。

针对获取数据库的数据,博主还没有学,浅浅根据网络资料说明一下,后买学了再详解。

在 Spring 配置文件中,你可以使用 Spring 的表达式语言(SpEL)来引用数据库中的数据,并将其作为参数值传递给 Bean 的构造函数。

public class AddressDao {private JdbcTemplate jdbcTemplate;public AddressDao(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public Address getAddressById(int id) {String sql = "SELECT street, city, country FROM address WHERE id = ?";return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> {String street = rs.getString("street");String city = rs.getString("city");String country = rs.getString("country");return new Address(street, city, country);});}
}

假设你有一个数据库表 person 存储了每个人的姓名、年龄和地址信息,你可以通过 Spring 的 JdbcTemplate 或者其他持久化框架来查询数据库并获取数据。然后,你可以将这些数据传递给 Person 类的构造函数。

<bean id="addressDao" class="com.example.AddressDao"><constructor-arg ref="dataSource" />
</bean><bean id="person" class="com.example.Person"><constructor-arg value="John Doe" /><constructor-arg value="30" /><constructor-arg expression="@addressDao.getAddressById(1)" />
</bean>

这样,Person 类就可以接收来自数据库的动态数据,并根据需要实例化对象。这种方式使得代码更具灵活性和可维护性,因为数据和代码的逻辑被分离开来,易于管理和修改。

当然,Spring框架中IoC实现方式不止基于xml的配置方式,还有基于注解的,具体等博主后面学习了再进行详解。

咕咕咕……

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务学习(黑马)

学习黑马的微服务课程的笔记 导学 微服务架构 认识微服务 SpringCloud spring.io/projects/spring-cloud/ 服务拆分和远程调用 根据订单id查询订单功能 存在的问题 硬编码 eureka注册中心 搭建eureka 服务注册 在order-service中完成服务拉取 Ribbon负载均衡 Nacos注册中心…

政安晨:【Keras机器学习实践要点】(二十五)—— 使用 EANet(外部注意力转换器)进行图像分类

目录 简介 设置 准备数据 配置超参数 使用数据增强 实施补丁提取和编码层 实施外部关注模块 实施 MLP 模块 执行变压器模块 实施 EANet 模式 培训 CIFAR-100 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机…

Flutter - flutter_gen 资源管理

引言&#xff1a; 在开发 Flutter 应用时&#xff0c;我们经常需要使用各种静态资源&#xff0c;如图片、字体和音频等。如何有效地管理和加载这些资源呢&#xff1f;本篇博客将以图片为例带你解密 Flutter 项目中是如何管理资源地。 assets 加载资源 具体文件名引入 在工程…

Leetcode 239. 滑动窗口最大值和Leetcode 347. 前 K 个高频元素

目录标题 Leetcode 239. 滑动窗口最大值题目描述C语言代码和题解解题思路 Leetcode 347. 前 K 个高频元素题目描述C语言题解和思路解题思路 Leetcode 239. 滑动窗口最大值 题目描述 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最…

[Kubernetes[K8S]集群:Slaver从节点初始化和Join]:添加到主节点集群内

文章目录 操作流程&#xff1a;上篇主节初始化地址&#xff1a;前置&#xff1a;Docker和K8S安装版本匹配查看0.1&#xff1a;安装指定docker版本 **[1 — 8] ** [ 这些步骤主从节点前置操作一样的 ]一&#xff1a;主节点操作 查看主机域名->编辑域名->域名配置二&#x…

STM32学习和实践笔记(9): 使用位带操作实现LED闪的实验

控制GPIO的那些寄存器&#xff0c;都在位带区。 根据上一篇讲的原理&#xff0c;要想每次只操作这些寄存的某一个bit而不影响别的bit&#xff0c;可以使用与这些bit相对应的位带别名区。 因此&#xff0c;在使用GPIO的位带操作之前&#xff0c;先要按上篇讲的原理&#xff0c…

通过前缀和来看golang的acm输入输出

前缀和 问题引入 package mainimport ("fmt" )func main() {var n, q, l, r intfmt.Scan(&n, &q)a : make([]int, n)ap : make([]int64, n 1)ap[0] 0for i : 0; i < n; i {fmt.Scan(&a[i])ap[i 1] ap[i] int64(a[i])}for j : 0; j < q; j {f…

远程桌面无法连接怎么办?

远程桌面无法连接是指在尝试使用远程桌面功能时出现连接失败的情况。这种问题可能会给工作和生活带来极大的不便&#xff0c;因此我们需要寻找解决办法。在讨论解决方案之前&#xff0c;我们先来了解一下【天联】组网的优势。 【天联】组网的优势有很多。它能够解决复杂网络环境…

[大模型]Qwen1.5-7B-Chat-GPTQ-Int4 部署环境

Qwen1.5-7B-Chat-GPTQ-Int4 部署环境 说明 Qwen1.5-72b 版本有BF16、INT8、INT4三个版本&#xff0c;三个版本性能接近。由于BF16版本需要144GB的显存&#xff0c;让普通用户忘却止步&#xff0c;而INT4版本只需要48GB即可推理&#xff0c;给普通用户本地化部署创造了机会。&…

MySQL数据库的详解(1)

DDL&#xff08;数据库操作&#xff09; 查询 查询所有数据库&#xff1a;show databases;当前数据库&#xff1a;select database(); 创建 创建数据库&#xff1a;create database [ if not exists] 数据库名 ; 使用 使用数据库&#xff1a;use 数据库名 ; 删除 删除数…

Deblurring 3D Gaussian Splatting去模糊3D高斯溅射

Abstract 摘要 Recent studies in Radiance Fields have paved the robust way for novel view synthesis with their photorealistic rendering quality. Nevertheless, they usually employ neural networks and volumetric rendering, which are costly to train and impede…

如何将普通maven项目转为maven-web项目

文件-项目结构&#xff08;File-->Project Structure &#xff09; 模块-->learn&#xff08;moudle-->learn&#xff09; 选中需要添加web的moudle&#xff0c;点击加号&#xff0c;我得是learn&#xff0c;单击选中后进行下如图操作&#xff1a; 编辑路径 结果如下…

微信小程序自定义关闭按钮在弹窗下面的效果

效果图: 我之前用vant 的popup的弹窗写&#xff0c;会出现close图标移动到弹窗内容外部不可见。 自定义代码&#xff1a; popup.JS/*** 生命周期函数--监听页面初次渲染完成*/onReady() {//自定义弹窗 动态获取屏幕高度var that this;wx.getSystemInfo({success: (result) &…

4.2.k8s的pod-标签管理、镜像拉取策略、容器重启策略、资源限制、优雅终止

一、标签管理 1.标签在k8s中极其重要&#xff0c;大多数资源的相互关联就需要使用标签&#xff1b;也就是说&#xff0c;资源的相互关联大多数时候&#xff0c;是使用标签进行关联的&#xff1b; 2.其他作用&#xff0c;在k8s集群中&#xff0c;node节点的一些操作比如污点及污…

前端docker jenkins nginx CI/CD持续集成持续部署-实战

最近用go react ts开发了一个todolist后端基本开发完了,前端采用CI/CD方式去部署。 步骤总结 先安装docker 和 docker-compose。安装jenkins镜像,跑容器的时候要配好数据卷。配置gitee或github(我这里使用gitee)在服务器上一定要创建好dokcer的数据卷,以便持久保存jenkin…

Google 推出 Gemini 1.5 Pro能处理音频;iOS 18或带来Safari 浏览助手;Llama 3 开源模型下个月推出

Google 推出 Gemini 1.5 Pro 公共预览版&#xff0c;能处理音频 Google 宣布将通过其 AI 应用平台 Vertex AI 向公众提供 Gemini 1.5 Pro&#xff0c;并且还赋予其「听力」&#xff0c;帮助用户处理音频内容。 用户可以上传会议录音、电视节目等音频内容&#xff0c;无需书面记…

好用的Python开发工具合集

​ Python是一种功能强大且易于学习的编程语言&#xff0c;被广泛应用于数据科学、机器学习、Web开发等领域。随着Python在各个领域的应用越来越广泛&#xff0c;越来越多的Python开发工具也涌现出来。但是&#xff0c;对于新手来说&#xff0c;选择一款合适的Python开发工具可…

R语言绘制一次和二次相关性热图

在数据探索的过程中&#xff0c;我们往往会对数据与数据的相关性进行分析&#xff0c;例如我们常用的corrplot包&#xff0c;或者psych包中的corr.test函数&#xff0c;对两两变量间的相关性进行分析。我们常常会看到这样的相关性热图&#xff1a; 但有时变量间的关系并非线性…

如何排查k8s集群中Pod内mysqld进程占用内存消耗过高?

文章目录 1. **查看容器资源使用情况**&#xff1a;2. **进入容器内部**&#xff1a;3. **检查进程内存使用**&#xff1a;4. **MySQL服务器状态检查**&#xff1a;5. **MySQL日志分析**&#xff1a;6. **使用专门的MySQL监控工具**&#xff1a;7. **配置文件检查**&#xff1a…

多模态 ——LLaVA 集成先进图像理解与自然语言交互GPT-4的大模型

概述 提出了一种大型模型 LLaVA&#xff0c;它使用 GPT-4 生成多模态语言图像指令跟随数据&#xff0c;并利用该数据将视觉和语言理解融为一体。初步实验表明&#xff0c;LLaVA 展示了出色的多模态聊天能力&#xff0c;在合成多模态指令上的表现优于 GPT-4。 在科学质量保证中…