Java阶段三02

第3章-第2节

一、知识点

面向接口编程、什么是spring、什么是IOC、IOC的使用、依赖注入

二、目标

  • 了解什么是spring

  • 理解IOC的思想和使用

  • 了解IOC的bean的生命周期

  • 理解什么是依赖注入

三、内容分析

  • 重点

    • 了解什么是spring

    • 理解IOC的思想

    • 掌握IOC的使用

  • 难点

    • 理解IOC的思想

    • 掌握IOC的使用

四、内容

1、Spring

1.1 简介

spring是分层的java SE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:控制反转)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业级应用开源框架。

1.2 优势
  • 开源免费的轻量级框架

  • 低侵入式设计,代码污染极低

  • 支持事务的处理,对框架整合的支持

  • 以控制反转(IOC),面向切面编程(AOP)为内核

  • 方便解耦,简化开发:将对象的创建交给spring 无需new

  • 提供了展现层SpringMVC和持久层Spring JDBCTemplate以及业务层事务管理等众多企业级应用技术

  • 能整合开源世界众多第三方框架和类库

1.3 引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>

2、Ioc

2.1 概念

控制反转(IoC,Inversion of Control)是一个概念,是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,依赖的管理。

以前我们在代码中,使用new 构造方法创建对象,现在不用了, 由容器代替开发人员管理对象。

2.2 传统方式和ioc方式的区别
  • 传统

    我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,每个对象在需要使用他的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起。

  • ioc

    创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。

下面用制造汽车需要引擎、轮胎等零件的场景解释含义

  • 假设现在要生产汽车、货车、客车、出租车,它们都是使用【1代引擎】

 

代码如下:

public class EngineV1 {
​private String name = "1代引擎";
​public String getName() {return name;}
}
/*** 汽车*/
public class Car {
​private String carName = "小汽车";
​private EngineV1 engineV1;
​public Car(EngineV1 engineV1) {this.engineV1 = engineV1;}
​public void info() {System.out.println(carName + "使用的是" + engineV1.getName());}
}
/*** 货车*/
public class Van {
​private String carName = "货车";
​private EngineV1 engineV1;
​public Van(EngineV1 engineV1) {this.engineV1 = engineV1;}
​public void info() {System.out.println(carName + "使用的是" + engineV1.getName());}
}

测试

Car car = new Car(new EngineV1());
car.info();
​
Van van = new Van(new EngineV1());
van.info();
​
// 结果
// 小汽车使用的是1代引擎
// 货车使用的是1代引擎

总结:现在可以看出不管是汽车还是货车,都是依赖于【1代引擎】的,耦合度很高,没有【1代引擎】就没有这些车。假如我们还有很多其他类型的车都是依赖于【1代引擎】,有一天我想把所有的【1代引擎】换成 【2代引擎】我该怎么做?全局搜索【1代引擎】修改为 【2代引擎】,想想都有点麻烦。

  • 我们需要换一种思路来实现,解决上述问题。

 

/*** 引擎接口*/
public interface IEngine {String getName();
}
public class EngineV1 implements IEngine{
​private String name = "1代引擎";
​public String getName() {return name;}
}
public class EngineV2 implements IEngine{
​private String name = "2代引擎";
​public String getName() {return name;}
}
/*** 汽车*/
public class Car {
​private String carName = "小汽车";
​// 现在不依赖于具体哪个引擎,直接对接引擎接口private IEngine engine;
​public Car(IEngine engine) {this.engine = engine;}
​public void info() {System.out.println(carName + "使用的是" + engine.getName());}
}
/*** 货车*/
public class Van {
​private String carName = "货车";
​private IEngine engine;
​public Van(IEngine engine) {this.engine = engine;}
​public void info() {System.out.println(carName + "使用的是" + engine.getName());}
}

测试

Car car = new Car(new EngineV1());
car.info();
​
Van van = new Van(new EngineV1());
van.info();
​
// 结果
// 小汽车使用的是1代引擎
// 货车使用的是1代引擎
Car car = new Car(new EngineV2());
car.info();
​
Van van = new Van(new EngineV2());
van.info();
​
// 结果
// 小汽车使用的是2代引擎
// 货车使用的是2代引擎

总结:代码中不再依赖于具体,而是依赖于抽象容器,即要针对接口编程,不针对实现编程。过去思维中想要什么依赖,需要自己去 “拉” 改为抽象容器主动 “推” 给你,你只管使用实体就可以了。这是依赖倒转 (DIP) 的一种表现形式。由原来的汽车依赖引擎转化成了引擎依赖引擎接口了,进行了反转。现在生产汽车的时候,给汽车什么引擎它就用什么引擎,汽车就脱离了只能用【1代引擎】绝对绑定形式了。

我们还可以接着优化,现在是使用引擎的时候我们手动去new的。假如项目中有很多的地方使用了【1代引擎】,要换成【2代引擎】,即把全部的new EngineV1()改成new EngineV2()

  • 针对上面的问题进行优化。我们可以先创建一个仓库出来,把引擎先创建好放在容器里面。车辆要用引擎的时候直接从仓库里面获取。

 

/*** 容器*/
public class Container {
​private Map<String, Object> map = new HashMap<String, Object>();
​public Container() {// 此处利用可以利用读取配置的方式,利用反射动态创建出对象map.put("engine", new EngineV1());}
​public Object getBean(String name) {return map.get(name);}
}

测试

// 创建容器
Container container = new Container();
​
Car car = new Car((IEngine) container.getBean("engine"));
car.info();
​
Van van = new Van((IEngine) container.getBean("engine"));
van.info();
​
// 结果
// 小汽车使用的是1代引擎
// 货车使用的是1代引擎

现在要把【1代引擎】化成【2代引擎】,我们只需要修改容器里面的引擎即可,只要修改一处地方。

map.put("engine", new EngineV2());

上面的测试结果就变成了

// 创建容器
Container container = new Container();
​
Car car = new Car((IEngine) container.getBean("engine"));
car.info();
​
Van van = new Van((IEngine) container.getBean("engine"));
van.info();
​
// 结果
// 小汽车使用的是2代引擎
// 货车使用的是2代引擎

总结:这就是IOC要做的事情。把创建对象的过程交给spring管理,我们需要用的时候直接拿就行。

3、基本使用

3.1 方式一:配置文件
  • 创建xml文件 resources/文件名.xml

  • 创建类
  • xml配置

    <!--  id:spring生成对象的时候,放到容器里面,会给每一个对象生成一个id,用于区分对象  -->
    <!--  class:告诉它使用哪个类  -->
    <bean id="student" class="com.company.eneity.Student">

  • 获取对象
    • 通过id获取
      public static void main(String[] args) {// 生成spring容器// 读取spring的xml文件,根据内容生成对应的对象,放到容器里面ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");// 获取对象,传入id,通过id获取对象Student student = (Student) ctx.getBean("student");System.out.println(student);
      }

    • 通过类获取
      public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");Student student1 = ctx.getBean(Student.class);System.out.println(student1);
      }

3.2 方式二:注解
  • 创建类
    // spring扫描到这个注解的时候,会自动生成对象
    @Component
    public class Teacher {}

  • 配置xml的component-scan
    <!-- 扫描包,会去扫描注解,有对应注解的会自动生成对象 -->
    <context:component-scan base-package="com.company"></context:component-scan>

  • 获取对象
    @Component
    public class TeacherDao {private Teacher teacher;public void test(){System.out.println(teacher);}
    }
    ​
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
    TeacherDao teacherDao = ctx.getBean(TeacherDao.class);
    teacherDao.test();
    3.3 bean的生命周期

spring默认的是单例对象可以通过scope修改

  • 单例对象

    scope="singleton"

    创建bean的时候使用默认的无参构造函数

    一个应用只有一个对象的实例,它的作用范围就是整个应用

    生命周期

    对象出生:当应用加载,创建容器时,对象就被创建

    对象活着:只要容器在,对象一直活着

    对象死亡:当应用卸载,销毁容器时,对象就被销毁了

    测试
    // 创建spring容器
    // 创建容器的时候,对象已经生成
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
    ​
    // 获取对象只是从容器里面拿出来
    Student student1 = (Student) ctx.getBean("student");
    Student student2 = (Student) ctx.getBean("student");
    ​
    System.out.println(student1 == student2);
    // 结果 true

  • 多例对象

    scope="prototype"

    每次访问对象时,都会被重新创建对象实例

    生命周期

    对象出生:当使用对象时,创建新的对象实例

    对象活着:对象在使用中,对象就一直活着

    对象死亡:当对象长时间不用,被java垃圾回收机制回收

    测试
    // 创建spring容器
    // 创建容器的时候对象还没有生成
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
    ​
    // 获取对象的时候才创建对象
    Student student1 = (Student) ctx.getBean("student");
    Student student2 = (Student) ctx.getBean("student");
    ​
    System.out.println(student1 == student2);
    ​
    // 结果 false

4、依赖注入

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。

4.1 使用构造函数

前提:类中需要提供一个对应参数列表的构造函数

标签:constructor-arg

标签属性:

index:指定参数在构造函数参数列表中的索引位置

type:指定参数在构造函数中的数据类型

name:指定参数在构造函数中的名称,用这个找给谁赋值

value:它能赋的值是基本数据类型和String类型

ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean

  • 基本数据类型(数值类和字符串类)

    基本数据类型直接用value赋值

    <bean id="student" class="com.company.eneity.Student"><!-- constructor-arg调用有参否则函数,必须有写构造函数 --><constructor-arg name="name" value="张三"></constructor-arg><constructor-arg name="age" value="18"></constructor-arg>
    </bean>

  • 引用数据类型

    引用数据类型使用ref赋值

    <bean id="student" class="com.company.eneity.Student"><!-- constructor-arg调用有参否则函数,必须有写构造函数 --><constructor-arg name="name" value="张三"></constructor-arg><constructor-arg name="age" value="18"></constructor-arg><constructor-arg name="studentMarjor" ref="studentMarjor"></constructor-arg>
    </bean>

4.2 使用set赋值

标签:property

标签属性:

name:找的是类中set方法后面的部分

value:给属性赋值的是基本数据类型和String类型

ref:给属性赋值是其他bean类型的

  • 基本数据类型
    <bean id="student2" class="com.company.eneity.Student2"><!-- property调用set的方法,必须set方法 --><property name="name" value="张三"></property><property name="age" value="18"></property>
    </bean>

  • 引用数据类型
    <bean id="student" class="com.company.eneity.Student"><property name="name" value="张三"></property><property name="age" value="18"></property><property name="studentMarjor" ref="studentMarjor"></property>
    </bean>
    <bean id="studentMarjor" class="com.company.eneity.StudentMarjor"><property name="name" value="软件工程"></property><property name="studentNum" value="80"></property>
    </bean>

5、小结

本章节中我们学习了什么是Spring,spring的优势是什么,为什么要用spring,同时学习了spring的一个核心功能IOC(控制反转),理解了控制反转的作用以及为什么要用控制反转,同时理解了什么是依赖注入,学会了通过XML文件配置IOC和不同方式的依赖注入。

下一节中,我们将会学习一些Spring的常用注解,学会使用注解进行开发,去理解注解开发和配置文件开发的区别和优势。

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

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

相关文章

Android Preference浅析(设置Setting)

各位&#xff0c;好久不见&#xff0c;最近时间较为充裕&#xff0c;更新一下博客。 本篇在我的理解、认识范围内&#xff0c;讲述一下Android中的Preference&#xff08;破粉斯~&#xff09;这玩意&#xff0c;常用于项目中的设置模块中。在工作中我也主要负责了设置模块相关…

鸿道Intewell操作系统架构介绍之Intewell-Hyper I 虚拟化构型

鸿道Intewell-Hyper I 虚拟化构型是鸿道Intewell-V虚拟化架构下的构型体系&#xff01;鸿道Intewell-V是科东软件自主研发的实时虚拟化操作系统&#xff0c;包括鸿道Intewell-Hyper I 和鸿道Intewell-Hyper II。鸿道Intewell-V可以实现多个操作系统在同一物理硬件上并行运行&am…

讲一讲 kafka 的 ack 的三种机制?

大家好&#xff0c;我是锋哥。今天分享关于【K讲一讲 kafka 的 ack 的三种机制&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; 讲一讲 kafka 的 ack 的三种机制&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Kafka的消息确认机制&…

多租户系统的应用架构

大家好&#xff0c;我是汤师爷~ 我们看下多租户系统的应用架构是如何从一层层构建起来的。 1、应用层设计 应用层的主要作用是为具体的用户场景提供应用服务&#xff0c;帮助用户在特定场景下完成操作。通过编排领域层的各项能力&#xff0c;实现SaaS产品的核心功能。应用层包…

波兰喜嘎嘎

之前做的一个项目&#xff0c;需要用c写一个服务去访问和控制硬件。这个服务是同事写的&#xff0c;今年年中离职了&#xff0c;很自然地&#xff0c;轮到我接手。 一、认知 我捣鼓了几天&#xff0c;勉强读懂一点原来的代码&#xff0c;并在原来基础上&#xff0c;做了一些修…

基于LORA的一主多从监测系统_4G模块上巴法云

临时添加一个更新&#xff0c;更换云平台为巴法云&#xff0c;事情的起因是因为阿里云这个老六&#xff0c;早上睡了一觉起来发短信告诉我云平台给我停了&#xff0c;得交钱&#xff0c;好嘛&#xff0c;不过也没办法现在这基本都收费&#xff0c;当然还有onenet可以用&#xf…

.NET Core WebApi第4讲:控制器、路由

一、控制器是什么&#xff1f; 1、创建一个空的API控制器&#xff1a;TestController.cs 2、里面有一个类叫TestController&#xff0c;把它叫做控制器 因为它继承了ControllerBase类&#xff0c;ControllerBase类里提供了一系列的方法&#xff0c;使得TestController这个类具…

Java面试经典 150 题.P55. 跳跃游戏(009)

本题来自&#xff1a;力扣-面试经典 150 题 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 题解&#xff1a; class Solution {public boolean canJump(int[] nums) {int…

计算机网络网络层笔记

互联网提供的两种服务 1.虚电路服务 2.数据报服务 需要记住的是现在只用第二种也就是数据报服务 网际协议IP 物理层的中断系统:转发器(hub) 链路层的中断系统:交换机 网络层的中断系统:路由器 网络层以上:网关 如上图所示,网关是用来访问其他的网段的一个接口,网关的地…

【热门主题】000015 大数据治理:开启数据价值新纪元

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

CentOS8.5.2111(4.1)数据中心主DNS部署

【背景】 某公司的数据中心DC&#xff0c;要架设DNS服务器负责解析“学生姓名缩写.cqie”的域名解析工作。DNS服务器的FQDN&#xff08;完全正式域名标识&#xff09;为dns.姓名.cqie&#xff0c;IP地址为192.168.学号.66。要求为以下域名实现正反向域名解析服务。&#xff08…

【C/C++】模拟实现strlen

学习目标&#xff1a; 使用代码模拟实现strlen。 逻辑&#xff1a; strlen 需要输入一个字符串数组类型的变量&#xff0c;并且返回一个整型类型的数据。strlen 需要计算字符串数组有多少个元素。 代码1&#xff1a;使用计数器 #define _CRT_SECURE_NO_WARNINGS 1 #include&…

渗透测试-百日筑基—SQL注入篇时间注入绕过HTTP数据编码绕过—下

day8-渗透测试sql注入篇&时间注入&绕过&HTTP数据编码绕过 一、时间注入 SQL注入时间注入&#xff08;也称为延时注入&#xff09;是SQL注入攻击的一种特殊形式&#xff0c;它属于盲注&#xff08;Blind SQL Injection&#xff09;的一种。在盲注中&#xff0c;攻击…

Linux 文件内容显示

文件内容显示 浏览普通文件 文件内容查看 cat 命令 作用&#xff1a;查看文件内容&#xff0c;适合数据量较少 格式&#xff1a; cat -参数 文件名 参数&#xff1a; -n &#xff1a;显示行号&#xff0c;加上 -b &#xff1a;文件中所有非空行增加行号&#xff0…

ALIGN: Tuning Multi-mode Token-level Prompt Alignment across Modalities

文章汇总 当前的问题 目前的工作集中于单模提示发现&#xff0c;即一种模态只有一个提示&#xff0c;这可能不足以代表一个类[17]。这个问题在多模态提示学习中更为严重&#xff0c;因为视觉和文本概念及其对齐都需要推断。此外&#xff0c;仅用全局特征来表示图像和标记是不…

linux学习笔记 Ubuntu下的守护进程supervisor安装与多项目部署

我这里首先是在本地WSL上进行安装&#xff0c;WSL2的是ubuntu 24.04&#xff0c;之后又再正式环境的ubuntu 20.04上安装&#xff0c;再次记录一下。 1、首先安装supervisor apt install -y supervisor 2、创建配置文件 echo_supervisord_conf > /etc/supervisor/supervisor…

Linux特种文件系统--tmpfs文件系统前传:虚拟内存子系统

虚拟内存子系统是操作系统中的一个重要组成部分&#xff0c;它负责管理和优化计算机的内存使用。虚拟内存的概念允许操作系统为每一个进程创建一个虚拟地址空间&#xff0c;这个空间比实际物理内存要大得多。虚拟内存子系统通过将部分虚拟地址映射到物理内存&#xff0c;部分映…

【测试工具】通过Jmeter压测存储过程

目录 一、存储过程准备1.1、 建立空表1.2、 建立存储过程1.3、调试 二、测试工具准备三、工具配置及执行3.1、配置JDBC Connection Configuration&#xff1a;3.2、配置吞吐量控制器3.3、配置JDBC Request 一、存储过程准备 1.1、 建立空表 CREATE TABLE test_data ( id NUMB…

安宝特分享 | AR技术引领:跨国工业远程协作创新模式

在当今高度互联的工业环境中&#xff0c;跨国合作与沟通变得日益重要。然而&#xff0c;语言障碍常常成为高效协作的绊脚石。安宝特AR眼镜凭借其强大的多语言自动翻译和播报功能&#xff0c;正在改变这一局面&#xff0c;让远程协作变得更加顺畅。 01 多语言翻译优势 安宝特A…