【SSM详细教程】-02-Spring容器IOC详解

embedded/2024/10/15 17:38:12/

精品专题:

01.《C语言从不挂科到高绩点》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482icon-default.png?t=O83Ahttps://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482

02. 《SpringBoot详细教程》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482icon-default.png?t=O83Ahttps://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.548203.《SpringBoot电脑商城项目》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482icon-default.png?t=O83Ahttps://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.548204.《VUE3.0 核心教程》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482icon-default.png?t=O83Ahttps://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482

================================

||   持续分享系列教程,关注一下不迷路  ||

||   视频教程:小破站:墨轩大楼             ||

================================

一、IOC 的概念

IOC全称是Inversion Of Control ,被译为控制反转。

指的是程序中对象的获取方式发生了反转,由最初的new方式创建,转变为由第三方框架创建、注入。第三方框架一般是通过配置方式注入一个具体实现,从而降低了对象之间的耦合度。

IOC按实现方法不同,可以分为依赖注入DI和依赖查找两种。Spring容器是采用DI实现了IOC控制,IOC是Spring框架的基础和核心。

举个例子,租房子时的两种选择。没有IOC之前,是租户自己和每一个房东交涉。有了IOC之后,IOC可以看作中介,找房子时,你只需要和这个中介打交道就可以,中介再分别和各个房东交涉,具体看下图:

二、DI 的概念

DI全称是Dependency Injection ,被译为依赖注入。

DI的基本原理就是将一起工作具有关系的对象,通过构造方法参数或者方法参数传入建立关联,因此容器的工作就是创建Bean时注入那些依赖关系。

IOC是一种思想,而DI是实现IOC的主要技术途径。

DI主要有两种注入方式,即Setter注入构造器注入

没有DI时我们创建和使用对象的方式:

java">Student muzi = new Student();
st.study()

使用DI之后创建和使用对象的方式:

三、setter注入

通过调用无参构造器或者无参static工厂方法实例化bean之后,调用该Bean的setter方法,即可实现setter方式注入。

  1. 首先自定义一个Computer类
java">package com.moxuan.spring01.entity;import java.io.Serializable;public class Computer implements Serializable {private String mainBoard;// 主板private String hdd;// 硬盘private String ram; //内存public String getMainBoard() {return mainBoard;}public void setMainBoard(String mainBoard) {this.mainBoard = mainBoard;}public String getHdd() {return hdd;}public void setHdd(String hdd) {this.hdd = hdd;}public String getRam() {return ram;}public void setRam(String ram) {this.ram = ram;}
}

  1. 在applicationContext.xml中配置setter注入
<!-- property : 表示实体类的属性name: 实体类属性名称value: 实体类属性值表示,将value值通过属性的set方法,设置到name属性中
-->
<bean id="computer" class="com.moxuan.spring01.entity.Computer"><property name="mainBoard" value="技嘉"></property><property name="hdd" value="希捷"></property><property name="ram" value="金士顿"></property>
</bean>
  1. 编写测试代码:
java">/**
* 测试setter注入
*/
@Testpublic void test05(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");Computer computer = context.getBean("computer",Computer.class);System.out.println(computer.getMainBoard());System.out.println(computer.getHdd());System.out.println(computer.getRam());
}

运行效果:

四、构造器注入

基于构造器的注入是通过调用带参数的构造器来实现的。容器在bean被实例化的时候,根据参数类型执行响应的构造器。

  1. 首先新建一个MobliePhone手机类
java">package com.moxuan.spring01.entity;public class MobilePhone {private String brand;private double price;public MobilePhone(String brand,double price){this.brand = brand;this.price = price;}public MobilePhone(){this.brand = "华为";this.price = 3999;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}
}

  1. 在applicationContext.xml中配置bean
<!--构造器注入: 有参数构造器-->
<bean id="phone" class="com.moxuan.spring01.entity.MobilePhone"><constructor-arg index="0" value="苹果"></constructor-arg><constructor-arg index="1" value="5999"></constructor-arg>
</bean><!--构造器注入: 无参数构造器--><bean id="noArgPhone" class="com.moxuan.spring01.entity.MobilePhone"></bean>

  1. 添加测试方法
java">/*** 测试构造器注入*/
@Test
public void test06(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");// 有参数构造器MobilePhone phone = context.getBean("phone",MobilePhone.class);System.out.println(phone.getBrand());System.out.println(phone.getPrice());// 无参数构造器MobilePhone phone1 = context.getBean("noArgPhone",MobilePhone.class);System.out.println(phone1.getBrand());System.out.println(phone1.getPrice());
}

  1. 运行结果:

五、自动装配

Spring IOC 容器可以自动装配(autowire)相互协作bean之间的关联关系。autowire可以针对单个bean进行设置,autowire的方法之处在于减少xml的注入配置。

在xml配置文件中,可以在<bean/>元素中使用autowire属性指定自动装配规则,一共有五种类型值。

属性值

描述

no

禁用自动装配,默认值

byName

根据属性名自动装配,此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。

byType

如果容器中存在一个与指定属性类型相同的bean,那么将于该属性自动装配。

constructor

与byType的方式类似,不同之处在于它应用于构造器函数

autodetect

通过bean类决定是使用constructor还是byType方式进行自动装配,如果发现默认的构造器,那么将使用byType方式。

5.1 测试byName

  1. 新增Student类
java">package com.moxuan.spring01.entity;public class Student {private Computer computer;private MobilePhone phone;public Computer getComputer() {return computer;}public void setComputer(Computer computer) {this.computer = computer;}public MobilePhone getPhone() {return phone;}public void setPhone(MobilePhone phone) {this.phone = phone;}
}

  1. 在applicationContext.xml中配置bean
<!-- setter 注入-->
<bean id="computer" class="com.moxuan.spring01.entity.Computer"><property name="mainBoard" value="技嘉"></property><property name="hdd" value="希捷"></property><property name="ram" value="金士顿"></property>
</bean><!--构造器注入: 有参数构造器-->
<bean id="phone" class="com.moxuan.spring01.entity.MobilePhone"><constructor-arg index="0" value="苹果"></constructor-arg><constructor-arg index="1" value="5999"></constructor-arg>
</bean><!--构造器注入: 无参数构造器-->
<bean id="noArgPhone" class="com.moxuan.spring01.entity.MobilePhone">
</bean><!--自动装配-->
<bean id="student" class="com.moxuan.spring01.entity.Student" autowire="byName"></bean>

  1. 添加测试方法
java">/**
* 测试自动装配
*/
@Test
public void test07(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");Student student = context.getBean("student",Student.class);System.out.println(student.getComputer().getHdd());System.out.println(student.getComputer().getMainBoard());System.out.println(student.getPhone().getBrand());System.out.println(student.getPhone().getPrice());}

  1. 运行效果

从运行效果可以看出,虽然配置文件中配置了两个MobliePhone类型的,但是由于我们自动装配的时候选择的是byName,会根据属性名去匹配,也就是会找到xml文件中id或者name和属性名相同的bean去装配。

5.2 测试byType

首先我们先将上一个案例中的autowire="byName" 修改为 autowire="byType"

这个时候就会出现问题,从报错信息来看,是说配置了多个MobilePhone类型的bean,如果这个时候按照类型装配的话,不知道该装配哪个,会有冲突。所以当使用byType的时候,xml配置文件中,不能出现多个同种类型的bean。

我们把id="phone"的bean注释掉

<!--构造器注入: 无参数构造器-->
<bean id="noArgPhone" class="com.moxuan.spring01.entity.MobilePhone"></bean><!--自动装配-->
<bean id="student" class="com.moxuan.spring01.entity.Student" autowire="byType"></bean>

测试代码不变

java">/**
* 测试自动装配
*/
@Test
public void test07(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");Student student = context.getBean("student",Student.class);System.out.println(student.getComputer().getHdd());System.out.println(student.getComputer().getMainBoard());System.out.println(student.getPhone().getBrand());System.out.println(student.getPhone().getPrice());}

测试结果

六、作业练习

6.1 利用Spring实现Bean属性Setter方式注入

JDBCDataSource类封装了管理数据库连接的方法getConnection(),这个方法在执行之前需要数据库连接参数:数据库驱动,连接URL,用户名和密码,代码如下:

java">package com.moxuan.spring01.entity;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class JDBCDataSource {private String driver;private String url;private String user;private String password;public String getDriver() {return driver;}public void setDriver(String driver) {try{// 注册数据库驱动Class.forName(driver);this.driver = driver;}catch (Exception e){e.printStackTrace();}}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getUser() {return user;}public void setUser(String user) {this.user = user;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Connection getConnection(){Connection conn = null;try {conn = DriverManager.getConnection(url,user,password);} catch (SQLException throwables) {throwables.printStackTrace();}return conn;}public void close(Connection conn){if(conn!=null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}
}

请利用Spring实现JDBCDataSource对象的创建,再使用setter注入的方式将数据库连接参数注入给JDBCDataSource。实现正常调用getConnection()方法获得数据库连接。

步骤一:在pom文件中导入mysql数据库所需要的依赖

<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.31</version>
</dependency>

步骤二:在applicationContext.xml中,增加setter代码注入JDBC参数

  <bean id="dataSource" class="com.moxuan.spring01.entity.JDBCDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://@localhost:3306/student"></property><property name="user" value="root"></property><property name="password" value="123456"></property></bean>

步骤三:在测试类中添加测试方法

java">/**
* 测试setter注入jdbc连接参数
*/
@Test
public void test08(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");JDBCDataSource dataSource = context.getBean("dataSource",JDBCDataSource.class);Connection conn = dataSource.getConnection();System.out.println(conn);
}

运行效果:

6.2 利用构造器参数实现依赖属性的注入

MysqlHeroDao是经典的数据库访问接口的实现类,这个类工作必须依赖mysql数据库连接来工作。JDBCDataSource实例可以提供mysql数据库的连接。MysqlHeroDao类采用构造器参数的方式依赖JDBCDataSource类,这样的好处是创建MysqlHeroDao对象必须有参数JDBCDataSource对象实例。

请完成以下几个练习:

  1. 请新建Hero类,添加id,name(名称),job(职业),sex(性别)等属性。
  2. 请在mysql数据库中添加hero表,添加id,name,job,sex等字段,并添加几条数据。
  3. 创建HeroDao接口,定义根据id查询英雄数据的接口。
  4. 创建MysqlHeroDao类,使用构造器注入的方式,注入JDBCDataSource,获取数据库连接,并实现HeroDao接口中定义的功能。
  5. 编写测试类,给定一个id能查询出对应id的英雄数据。

步骤一:新建Hero.java实体类

java">@Data
public class Hero implements Serializable {private Integer id;private String name;private String job;private String sex;
}

此处使用了lombok自动添加了get和set方法。

步骤二:在数据库中新增hero表,脚本如下:

DROP TABLE IF EXISTS `hero`;
CREATE TABLE `hero` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(30) DEFAULT NULL,`job` varchar(30) DEFAULT NULL,`sex` varchar(30) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of hero
-- ----------------------------
INSERT INTO `hero` VALUES ('1', '后羿', '射手', '男');
INSERT INTO `hero` VALUES ('2', '甄姬', '法师', '女');
INSERT INTO `hero` VALUES ('3', '典韦', '战士', '男');
INSERT INTO `hero` VALUES ('4', '蔡文姬', '辅助', '女');

步骤三:创建HeroDao接口,并定义根据ID查找数据的功能

java">public interface HeroDao {/** 根据id查找英雄数据**/Hero findHeroById(int id);
}

步骤四:创建MysqlHeroDao,实现HeroDao接口,并实现里面的功能

java">package com.moxuan.spring01.entity;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class MysqlHeroDao implements HeroDao{private JDBCDataSource dataSource;public MysqlHeroDao(JDBCDataSource dataSource){this.dataSource = dataSource;}@Overridepublic Hero findHeroById(int id) {Connection con =  dataSource.getConnection();String sql = "select * from hero where id=?";try {PreparedStatement pst = con.prepareStatement(sql);pst.setInt(1,id);ResultSet rs = pst.executeQuery();Hero hero = null;if(rs.next()){hero = new Hero();hero.setId(rs.getInt("id"));hero.setName(rs.getString("name"));hero.setJob(rs.getString("job"));hero.setSex(rs.getString("sex"));}con.close();return hero;} catch (SQLException throwables) {throwables.printStackTrace();}return null;}
}

步骤五:在applicationContext.xml中配置MysqlHeroDao,并利用构造器注入datasource。

  <bean id="dataSource" class="com.moxuan.spring01.entity.JDBCDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://@localhost:3306/student"></property><property name="user" value="root"></property><property name="password" value="123456"></property></bean><bean id="heroDao" class="com.moxuan.spring01.entity.MysqlHeroDao"><!-- 引用上面的datasource--><constructor-arg index="0" ref="dataSource"></constructor-arg></bean>

上面代码中dataSource为按构造参数注入,这个参数是引用了id为dataSource的Bean对象。

步骤六:编写测试方法

java">@Test
public void test09(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");HeroDao dao = context.getBean("heroDao",MysqlHeroDao.class);Hero hero = dao.findHeroById(1);System.out.println(hero);
}

运行效果:

6.3 利用Spring自动装配功能实现自动属性注入

HeroService类需要依赖HeroDao接口的实例实现查询hero数据的功能,也就是说要能够正确执行HeroService类型对象的查询hero数据的方法必须为HeroService对象注入HeroDao类型的实例。

请使用Spring自动装配的方式为HeroService提供HeroDao对象的实例。

步骤一:添加HeroService类,并添加根据id查询hero的方法

java">package com.moxuan.spring01.entity;public class HeroService {private HeroDao heroDao;public HeroDao getHeroDao() {return heroDao;}public void setHeroDao(HeroDao heroDao) {this.heroDao = heroDao;}public Hero getHeroById(int id){return heroDao.findHeroById(id);}
}

步骤二:在applicationContext.xml中将heroDao自动装配到HeroService中。

<bean id="dataSource" class="com.moxuan.spring01.entity.JDBCDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://@localhost:3306/student"></property><property name="user" value="root"></property><property name="password" value="123456"></property>
</bean><bean id="heroDao" class="com.moxuan.spring01.entity.MysqlHeroDao"><!-- 引用上面的datasource--><constructor-arg index="0" ref="dataSource"></constructor-arg>
</bean><bean id="heroService" class="com.moxuan.spring01.entity.HeroService" autowire="byType"></bean>

步骤三: 编写测试方法

java">@Test
public void test10(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");HeroService service = context.getBean("heroService",HeroService.class);Hero hero = service.getHeroById(2);System.out.println(hero);}

http://www.ppmy.cn/embedded/127987.html

相关文章

StringEntity 用于将字符串内容作为 HTTP 请求实体(请求体)

StringEntity 类是 Apache HttpClient 库中的一个类&#xff0c;它用于将字符串内容作为 HTTP 请求实体&#xff08;请求体&#xff09;。这个类非常适合用于发送 JSON、XML 或其他需要以字符串形式发送的数据。以下是 StringEntity 类的一些常用方法和代码案例&#xff1a; …

场内期权交易规则及方式详解

场内期权是一种在场内二级市场交易的金融衍生品&#xff0c;场内期权就是赋予持有者在未来某个时间以特定价格买入或卖出某种资产的权利&#xff0c;但不是义务。场内期权在交易所内交易&#xff0c;具有标准化合约、高流动性和透明度。 场内期权的交易规则 1. 合约标准化&am…

web端使用高德地图逆地理编码

1、首先去地理/逆地理编码-基础 API 文档-开发指南-Web服务 API | 高德地图API注册一下 2、点击产品介绍-------地理/逆地理编码 3、创建应用拿到key 创建web服务、看底下有逆地理编码服务 4、上一步就能拿到key了最后一步复制底下代码即可 <!DOCTYPE html> <html l…

IPv4数据报的首部格式 -计算机网络

IPv4数据报的首部格式 Day22. IPv4数据报的首部格式 -计算机网络_4字节的整数倍-CSDN博客 IP数据报首部是4字节的整数倍 &#x1f33f;版本&#xff1a; 占4比特&#xff0c;表示IP协议的版本通信双方使用的IP协议必须一致&#xff0c;目前广泛使用的IP协议版本号上4&#xf…

论文阅读笔记-Self-Attention

前言 Self-Attention能够将每个元素和当前时刻元素进行比较来确定上下文元素的重要性,这也使得它在NLP模型中表现优异。而本篇文章则是将卷积结构与Self-Attention结构进行了比较,通过 实验证明了这样的卷积结构同样有着高效的计算和足以和Self-Attention媲美的效果。本篇文…

螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习07(基于docker容器的防火墙及NAT企业实战)

7.1 网络准备 7.2 网络规划 1&#xff09;虚拟网络编辑器 点击右下方“更改设置”&#xff0c;点击“添加网络”假如vmnet3和vmnet4&#xff0c;然后分别选择vmnet3和vmnet4&#xff0c;设置为“仅主机模式”&#xff0c;按③处处理&#xff0c;去掉“使用DHCP”&#xff0c;…

【DataSophon】DataSophon1.2.1 整合Zeppelin并配置Hive|Trino|Spark解释器

目录 ​一、Zeppelin简介 二、实现步骤 2.1 Zeppelin包下载 2.2 work配置文件 三、配置常用解释器 3.1配置Hive解释器 3.2 配置trino解释器 3.3 配置Spark解释器 一、Zeppelin简介 Zeppelin是Apache基金会下的一个开源框架&#xff0c;它提供了一个数据可视化的框架&am…

Python创建多个线程分别启动http、WebSocket服务

我的计划是启动主程序后新建3个独立的线程&#xff0c;一个线程执行PLC读取&#xff0c;一个线程启动工艺测试&#xff08;含http服务&#xff09;&#xff0c;另外一个线程启动WebSocket。 新增 /lib/PlcReader.py # 执行 PLC 读取类 # 读取 PLC 配置文件 # 定时&#xff08…