spring对IOC的实现

Ioc控制反转

  • 控制反转是一种思想。

  • 控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。

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

    • 将对象的创建权利交出去,交给第三方容器负责。
    • 将对象和对象之间关系的维护权交出去,交给第三方容器负责。
  • 控制反转这种思想如何实现呢?

    • DI(Dependency Injection):依赖注入

依赖注入

依赖注入实现了控制反转的思想。

Spring通过依赖注入的方式来完成Bean管理的。

Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

依赖注入:

  • 依赖指的是对象和对象之间的关联关系。
  • 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。

依赖注入常见的实现方式包括两种:

  • 第一种:set注入
  • 第二种:构造注入

set注入

set注入,基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求属性必须对外提供set方法。

public class UserDao {public void insert(){System.out.println("正在保存用户信息。。。。");}
}public class UserService {UserDao userDao;// 使用set方式注入,必须提供set方法。// 反射机制要调用这个方法给属性赋值的。public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}@org.junit.Testpublic void testDI(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);userServiceBean.save();System.out.println(userServiceBean);}
<bean id="userDaoBean" class="com.xun.dao.UserDao"></bean><bean id="userServiceBean" class="com.xun.service.UserService"><property name="userDao" ref="userDaoBean"></property></bean>

在这里插入图片描述

原理:

通过property标签获取到属性名:userDao

通过属性名推断出set方法名:setUserDao

通过反射机制调用setUserDao()方法给属性赋值

property标签的name是属性名。

property标签的ref是要注入的bean对象的id。(通过ref属性来完成bean的装配,这是bean最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)

通过测试得知,底层实际上调用了setUserDao()方法。所以需要确保这个方法的存在。

总结:set注入的核心实现原理:通过反射机制调用set方法来给属性赋值,让两个对象之间产生关系

构造注入

核心原理:通过调用构造方法来给属性赋值。

public class OrderDao {public void deleteById(){System.out.println("正在删除。。。");}
}public class OrderService {OrderDao orderDao;public OrderService(OrderDao orderDao) {this.orderDao = orderDao;}public void deleteById(){orderDao.deleteById();}
}@org.junit.Testpublic void testConstructorDI(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");OrderService orderServiceBean = applicationContext.getBean("orderServiceBean", OrderService.class);orderServiceBean.deleteById();}
<bean id="orderDaoBean" class="com.xun.dao.OrderDao"></bean><bean id="orderServiceBean" class="com.xun.service.OrderService"><!--如果有多个参数,那么index的值为构造函数中参数的下标--><!--<constructor-arg index="0" ref="orderDaoBean"></constructor-arg>--><!--<constructor-arg index="1" ref="userDaoBean"></constructor-arg>--><!--这里使用了构造方法上参数的名字--><constructor-arg name="orderDao" ref="orderDaoBean"></constructor-arg></bean>

在这里插入图片描述

通过测试得知,通过构造方法注入的时候:

  • 可以通过下标
  • 可以通过参数名
  • 也可以不指定下标和参数名,可以类型自动推断。

Spring在装配方面做的还是比较健壮的。

set注入专题

注入外部bean

    <bean id="userDaoBean" class="com.xun.spring6.dao.UserDao"/><bean id="userServiceBean" class="com.xun.spring6.service.UserService"><property name="userDao" ref="userDaoBean"/></bean>

注入内部bean

<bean id="userServiceBean" class="com.xun.spring6.service.UserService"><property name="userDao"><bean class="com.xun.spring6.dao.UserDao"/></property>
</bean>

注入简单类型

<bean id="userBean" class="com.xun.spring6.beans.User"><!--如果像这种int类型的属性,我们称为简单类型,这种简单类型在注入的时候要使用value属性,不能使用ref--><!--<property name="age" value="20"/>--><property name="age"><value>20</value></property>
</bean>

需要特别注意:如果给简单类型赋值,使用value属性或value标签。而不是ref。

注入数组

<bean id="person" class="com.xun.spring6.beans.Person"><property name="favariteFoods"><array><value>鸡排</value><value>汉堡</value><value>鹅肝</value></array></property></bean>

当数组中的元素是非简单类型:一个订单中包含多个商品。

<bean id="goods1" class="com.xun.spring6.beans.Goods"><property name="name" value="西瓜"/></bean><bean id="goods2" class="com.xun.spring6.beans.Goods"><property name="name" value="苹果"/></bean><bean id="order" class="com.xun.spring6.beans.Order"><property name="goods"><array><!--这里使用ref标签即可--><ref bean="goods1"/><ref bean="goods2"/></array></property></bean>
  • 如果数组中是简单类型,使用value标签。
  • 如果数组中是非简单类型,使用ref标签。

注入List集合

<bean id="peopleBean" class="com.xun.spring6.beans.People"><property name="names"><list><value>铁锤</value><value>张三</value><value>张三</value><value>张三</value><value></value></list></property></bean>

注入set集合

<bean id="peopleBean" class="com.xun.spring6.beans.People"><property name="phones"><set><!--非简单类型可以使用ref,简单类型使用value--><value>110</value><value>110</value><value>120</value><value>120</value><value>119</value><value>119</value></set></property>
</bean>
  • 使用标签
  • set集合中元素是简单类型的使用value标签,反之使用ref标签。

注入map集合

<bean id="peopleBean" class="com.xun.spring6.beans.People"><property name="addrs"><map><!--如果key不是简单类型,使用 key-ref 属性--><!--如果value不是简单类型,使用 value-ref 属性--><entry key="1" value="北京大兴区"/><entry key="2" value="上海浦东区"/><entry key="3" value="深圳宝安区"/></map></property></bean>
  • 使用标签
  • 如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。
  • 如果value是简单类型,使用 value 属性,反之使用 value-ref 属性。

注入properties

java.util.Properties继承java.util.Hashtable,所以Properties也是一个Map集合。

<bean id="peopleBean" class="com.xun.spring6.beans.People"><property name="properties"><props><prop key="driver">com.mysql.cj.jdbc.Driver</prop><prop key="url">jdbc:mysql://localhost:3306/spring</prop><prop key="username">root</prop><prop key="password">123456</prop></props></property>
</bean>
  • 使用标签嵌套标签完成。

注入null和空字符串

注入空字符串使用: 或者 value=“”

注入null使用: 或者 不为该属性赋值

<bean id="vipBean" class="com.xun.spring6.beans.Vip"><!--空串的第一种方式--><!--<property name="email" value=""/>--><!--空串的第二种方式--><property name="email"><value/></property>
</bean><bean id="vipBean" class="com.xun.spring6.beans.Vip"><property name="email"><null/></property>
</bean><bean id="vipBean" class="com.xun.spring6.beans.Vip" />

p命名空间注入

目的:简化配置。

使用p命名空间注入的前提条件包括两个:

  • 第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p=“http://www.springframework.org/schema/p”
  • 第二:p命名空间注入是基于setter方法的,所以需要对应的属性提供setter方法。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="customerBean" class="com.powernode.spring6.beans.Customer" p:name="zhangsan" p:age="20"/></beans>

c命名空间注入

c命名空间是简化构造方法注入的。

使用c命名空间的两个前提条件:

​ 第一:需要在xml配置文件头部添加信息:xmlns:c=“http://www.springframework.org/schema/c”

​ 第二:需要提供构造方法。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:c="http://www.springframework.org/schema/c"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--<bean id="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:year="1970" c:month="1" c:day="1"/>--><bean id="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:_0="2008" c:_1="8" c:_2="8"/></beans>

基于xml的自动装配

Spring还可以完成自动化的注入,自动化注入又被称为自动装配。它可以根据名字进行自动装配,也可以根据类型进行自动装配。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userService" class="com.powernode.spring6.service.UserService" autowire="byName"/><bean id="aaa" class="com.powernode.spring6.dao.UserDao"/></beans>

这个配置起到关键作用:

  • UserService Bean中需要添加autowire=“byName”,表示通过名称进行装配。
  • UserService类中有一个UserDao属性,而UserDao属性的名字是aaa,对应的set方法是setAaa(),正好和UserDao Bean的id是一样的。这就是根据名称自动装配。

根据类型自动装配

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--byType表示根据类型自动装配--><bean id="accountService" class="com.powernode.spring6.service.AccountService" autowire="byType"/><bean class="com.powernode.spring6.dao.AccountDao"/></beans>

xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>

<!--byType表示根据类型自动装配-->
<bean id="accountService" class="com.powernode.spring6.service.AccountService" autowire="byType"/><bean class="com.powernode.spring6.dao.AccountDao"/>
```

可以看到无论是byName还是byType,在装配的时候都是基于set方法的。所以set方法是必须要提供的。提供构造方法是不行的,当byType进行自动装配的时候,配置文件中某种类型的Bean必须是唯一的,不能出现多个

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

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

相关文章

硬盘温度过高会怎么办?机箱温度多少算正常?

硬盘温度 硬盘在使用过程中&#xff0c;断电很容易导致数据丢失&#xff0c;但如果温度过高&#xff0c;也可能对硬盘造成损坏。 硬盘的温度是决定电脑能否正常使用的重要因素。 如果长时间读取和存储数据&#xff0c;硬盘的温度会升高。 那么&#xff0c;硬盘的正常温度是多少…

代码随想录day16 栈与队列:前 K 个高频元素(leetcode347)

题目要求&#xff1a;给定一个非空的整数数组&#xff0c;返回其中出现频率前 k 高的元素。 思路&#xff1a;我们需要使用map来统计整个数组中元素出现的频率&#xff0c;然后再根据统计好的频率去排序&#xff0c;取得频率前K高的元素。我们不必使用快排实际上我们使用优先级…

Open CASCADE学习|表面着色显示模型

模型表面着色具有如下作用&#xff1a; 视觉增强&#xff1a;通过为模型表面添加着色&#xff0c;可以使其更加生动和逼真&#xff0c;提高视觉体验。 信息区分&#xff1a;在复杂的模型中&#xff0c;不同的部分或组件可能需要通过不同的颜色来区分&#xff0c;以便更清晰地…

20 卷积层里的填充和步幅【李沐动手学深度学习v2课程笔记】

1. 填充和步幅 在上下左右分别填充一些0 2. 代码实现 2.1 填充 我们创建一个高度和宽度为3的二维卷积层&#xff0c;并在所有侧边填充1个像素。给定高度和宽度为8的输入&#xff0c;则输出的高度和宽度也是8。 import torch from torch import nn# 为了方便起见&#xff0c;…

Xilinx 7系列 FPGA硬件知识系列(九)——FPGA的配置

目录 1 .1配置模式 1.1.1 主模式 1.1.2 从模式 1.2 7种配置模式 1.2.1 主串配置模式 1.2.2 从串配置模式 ​编辑1.2.3 主并配置模式 1.2.4 从并配置模式 1.2.5 JTAG配置模式 ​编辑1.2.6 主SPI配置模式 ​编辑1.2.7 主BPI配置模式 1.2.8 FPGA BPI加载时间…

【牛客】VL74 异步复位同步释放

描述 题目描述&#xff1a; 请使用异步复位同步释放来将输入数据a存储到寄存器中&#xff0c;并画图说明异步复位同步释放的机制原理 信号示意图&#xff1a; clk为时钟 rst_n为低电平复位 d信号输入 dout信号输出 波形示意图&#xff1a; 输入描述&#xff1a; clk为时…

RocketMQ -- 低时延、高性能、高可靠、万亿级容量、灵活扩展的分布式消息流式传输平台

第一章 RocketMQ 概述 一、RocketMQ 简介 1.1 消息队列 MQ&#xff08;Message Queue&#xff09;是一种提供消息队列服务的中间件&#xff0c;也称消息中间件&#xff0c;是一套提供了海量消息生产、存储、消费全过程 API 的软件系统。 MQ 的作用&#xff1a; 限流削峰异步…

静态时序分析:SDC约束命令set_case_analysis详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 目录 指定值 指定端口/引脚列表 简单使用 set_case_analysis命令用于对电路进行特定模式的设定&#xff0c;例如对于一个工作在正常模式下的芯片&#xff0c;…

Igraph入门指南 3

4、图转换到其他R数据结构 图是对实体关系的表达&#xff0c;在igraph中&#xff0c;图可以转换为三种数据结构。 4-1 图转邻接矩阵&#xff1a;as_adjacency_matrix | as_adj&#xff0c;结果是矩阵 邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵&#xff0c;但本函数使用…

Linux学习之线程

目录 线程概念 1.什么是线程&#xff1f; 2.线程的优缺点 3.线程异常 4.线程用途 线程操作 1.如何给线程传参 2.线程终止 3.获取返回值 4.分离状态 5.退出线程 线程的用户级地址空间&#xff1a; 线程的局部存储 线程的同步与互斥 互斥量mutex 数据不一致的主要过…

组合逻辑电路(二)(译码器和编码器)

目录 译码器 简单逻辑门译码器 二进制译码器 2线-4线译码器 3线-8线译码器 二-十进制译码器 4线-10线译码器 七段显示译码器 编码器 二进制普通编码器 二-十进制普通编码器&#xff08;8421BCD码编码器&#xff09; 优先编码器&#xff08;Priority Encoder&#xff09; 译…

(day 2)JavaScript学习笔记(基础之变量、常量和注释)

概述 这是我的学习笔记&#xff0c;记录了JavaScript的学习过程&#xff0c;我是有一些Python基础的&#xff0c;因此在学习的过程中不自觉的把JavaScript的代码跟Python代码做对比&#xff0c;以便加深印象。我本人学习软件开发纯属个人兴趣&#xff0c;大学所学的专业也非软件…