Spring05 SpringIOC DI

名词解释

今天我们来介绍Spring框架的最重要的part之一   SpringIOC 和 DI

这里的SpringIOC 其实是容器的意思,Spring是一个包含了很多工具方法的IOC容器

什么是IOC呢?

IOC其实是Spring的核心思想 

Inversion of Control  (控制反转)

可能这里你还是不理解这个是啥意思  其实就是我们一般创建对象的方式是使用new等方式创建,但是这里我们让Spring帮助我们创建对象,程序中只需要进行DI(对象注入)即可

Spring是一个IOC容器,所以有时候Spring也称之为Spring容器

这里举一个生活上的例子来解释一下SpringIOC的含义

我们招聘的时候,其实企业员工的入职和解雇等操作都得老板自己来,但是这里我们老板转给了HR来处理

案例对比

传统方式

假如我们需要实现这么一个依赖关系的思路

我们第一版本先使用传统方式进行操作一下

//轮胎
public class Tire {private int size;private String color;public Tire(int size) {System.out.println("tire size:"+size);}
}//底盘
public class Bottom {private Tire tire;public Bottom(int size) {tire = new Tire(size);System.out.println("tire init...");}
}//框架
public class Framework {private Bottom bottom;public Framework(int size) {bottom =  new Bottom(size);System.out.println("bottom init....");}
}//汽车
public class Car {private Framework framework;public Car(int size) {framework = new Framework(size);System.out.println("framework init...");}public void run() {System.out.println("car run...");}
}//启动类
public class Main {public static void main(String[] args){Car car = new Car(10);car.run();}
}

这里我们发现,我们如果对车万一需要进行一些操作,就会导致牵一发而动全身的效果

比如,如果我们为车的轮胎指定轮胎的厂家,这样我们就需要从轮胎类逐个的向上进行修改

这样程序的耦合度就太高了,于是我们现在介绍一下SpringIOC的方式来管理对象

注:这里只是模拟SpringIOC的方式来创建对象,这里SpringIOC其实我们也可以理解为一种思想,本质上要求交给Spring管理的对象是无状态的

SpringIOC版本

这里我们可以将对象的创建放到一块儿,Spring框架的想法是将对象的创建交给Spring来,我们向使用的时候只需要使用DI注入即可

这里我们先模拟一下程序的解耦,避免这种牵一发而动全身的操作存在

//bottom
public class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("tire init...");}
}//Car
public class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("framework init...");}public void run() {System.out.println("car run...");}
}//Framework
public class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("bottom init....");}
}//Tire
public class Tire {private int size;private String color;public Tire(int size, String color) {System.out.println("tire size:"+size+",color:"+color);}
}//Main
public class Main {public static void main(String[] args) {Tire tire = new Tire(17, "red");Bottom bottom = new Bottom(tire);Framework framework = new Framework(bottom);Car car = new Car(framework);car.run();}
}

这里我们发现了对象创建的思路是这样的

传统方式是创建Car再去找需求的依赖,是一个从下到上的结构

而IOC的方式是将对象依赖注入,是改进之后的控制权反转

这里我们可以看出IOC思维的优势

1.减少了类之间的耦合度

2.便于对象的集中管理

DI

解释就是依赖注入的意思,我们刚刚这种传对象的操作其实理论依据就是DI

IOC详解

下面我们进行SpringIOC的详解

首先我们提出一个Bean的概念 Spring中的对象称之为Bean

我们如果想把某些对象交给Spring管理,我们可以用以下注解来修饰

1.类注解

@Repository   @Service @Component  @Configuration   @Controller

2.方法注解

@Bean

注:Spring也不一定需要在web网页上显示,我们也可以在控制台打印

首先我们来尝试一下这五大类注解

@Component
public class UserComponent {public void doComponent(){System.out.println("UserComponent");}
}@Configuration
public class UserConfig {public void doConfig(){System.out.println("UserConfig doConfig");}
}@Repository
public class UserRepo {public void doRepo(){System.out.println("UserRepo");}
}@Service
public class UserService {public void doService() {System.out.println("UserService doService");}
}@Controller
public class helloTest {public void hello(){System.out.println("hello");}
}//启动类
@SpringBootApplication
public class SpringIocApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(SpringIocApplication.class, args);helloTest bean = context.getBean(helloTest.class);bean.hello();}}

这里我们只需要用相同的模板就可以实现这里的IOC操作

这里我们介绍一下getBean的几个参数

我们可以根据类型找到类,可以根据类型+方法名找到类,也可以只根据方法名寻找类

注意这里Bean的名字是以小驼峰的方式去拿的

比如HelloTest 这里的Bean名称就是 helloTest

注意这里获取到的三个对象都是同一个对象

类的命名规则:如果只有开头字母是大写的,那么我们就将第一个字母变成小写的,如果前两个都是大写字母,那么我们就直接返回这个名字

假设这里我们使用的类名是HElloTest,我们使用首字母小写小驼峰的方式就会直接失败

这里我们可以看到日志显示找不到这个Bean 实际上开头两个字母都大写Bean就不会修改名称,直接使用原名即可获取

使用的就是这个方法

注:idea中查询类 使用 ctrl + shift + alt + n

再查询方法可以使用ctrl + f查询

Application和BeanFactory之间的关系?

1.父子关系  BeanFactory有的功能Application都有

2.除此之外Application有很多其他的功能

3.BeanFactory是一个懒加载的方式  

Application是一个预加载的方式,效率更高

五大注解的对比

我们看到除了component其他的四大注解基本上都是一样的

可以混用嘛??

理论上可以,但是工作中一般不允许混用,但是其中的界限分割的不明确,有的时候还是混用的

@Controller   @Conponent  主键

@Service 业务逻辑层  @Repository  数据层 @Configuration  表现层

注:这里的Controller有特殊用处,其余三个可以在理论上混用(事实上也可以)

其余四个注解都包含了Component

注:@Controller如果进行替换不一定能实现路由映射

注:这里不加上注解时无法将对象交给Spring管理的

这里我将@Controller注解删除

Spring就会获取不到这个Bean

下面开始使用Bean的方式书写

注意:@Bean的使用也需要配合五大注解一起使用

Spring不可能扫描所有的项目文件,这里我们就使用五大注解来标识一下需要扫描的文件

@Bean的命名方式就是方法名

Spring扫描的默认是哪些文件呢?

我们先做一个测试,将启动类放到component包下

这时候去获取component的类就是可以的,获取HelloTest的类就是失败的

Spring扫描的三大条件

1.使用五大注解标记类

2.使用Bean注解标记方法

3.默认扫描路径是启动类所在的目录以及子目录 

如果我们向让其扫描其他的路径,就可以使用@ComponentScan(basePackages = "")

我们这样就可以获取User对象了

@Configuration
public class UserConfig {@Beanpublic User doConfig(){User u1 = new User();u1.setName("zhangsan");u1.setId(1001);return u1;}
}

DI注入

这里有三种方式注入

1.依赖注入/属性注入

2.构造器注入

3.setter注入

首先是依赖注入  我们只需要给需要交给Spring的对象加上五大注解,给需要注入的属性加上Autowired让他去Spring里面获取对应的对象即可

我们将注解干掉,使用构造器的方式也可以获取到

但是如果加上一个空参构造器,就会产生异常

这里出现空指针了,因为这里的Spring是调用构造函数来创建对象的,是使用反射的方式来操作的,这里有两个对应的构造函数了,默认就直接使用无参的构造函数了

如果我们再加一个属性和一个两个参数的构造函数

就会产生没有默认构造器的错误,这里我们可以使用@Autowired修饰默认构造方法解决

这样就可以正常运行啦

总结:

对于构造函数注入

1.只有一个构造函数的时候,无需操作

2.多个构造函数的时候需要@Autowired指定对应的构造函数

注:规范的写法是任何时候都把无参的构造函数加上,然后把想用的构造函数加上@Autowired注解即可

set方法+@autowired注解仍然可以完成任务

三种属性注入的优缺点

1.属性注入

优点是简洁并且书写方便

缺点也明显 只能用于IOC容器,使用的时候肯呢个出现空指针问题

不能注入final修饰的属性

2.构造器注入

优点:可以注入final修饰的属性

通用性好,JDK支持,所以任何框架都行

依赖对象使用前一定会被完全初始化

3.set方法注入

优点是方便在类实例之后重新堆起对象进行配置和注入

缺点是不能注入final修饰的属性

也可能被其他人修改

我们使用已有的bean来命名是可以正常执行内容的

但是只要我们改一下名字,立马就找不到对应的bean了

我们可以理解这里的查找方式是先根据类型和名称查询,查不到就根据类型查找,在没有就报错异常

这里可以使用三种方式去拿到对应的Bean对象

1.使用Primary注解给对应的Bean标记上,指定使用这个Bean

2.使用Qualifier注解,选出使用Bean的方法名

3.使用resourse注解加上方法名的方式也可以解决问题

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

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

相关文章

【LeetCode】128. 最长连续序列(Java自用版)

哈希集合 class Solution {public int longestConsecutive(int[] nums) {Set<Integer> set new HashSet<>();for (int num : nums) {set.add(num);}int ans 0;for (int num : set) {int cur num;if (!set.contains(cur - 1)) {while (set.contains(cur 1)) {c…

程序运行之ELF文件的段

更多精彩内容在公众号。 我们将之前的代码增加下变量来具体看下 在代码中增加了全局变量以及静态变量&#xff0c;还有一个简单的函数。 #include <stdio.h> int global_var1; int global_init_var; void func1(int i){ printf("%d\n",i); } int main(vo…

C++入门(一)

目录 命名空间&#xff1a; 为什么要提出命名空间&#xff1f; 命名空间的定义&#xff1a; 命名空间的使用&#xff1a; 加命名空间名称及作用域限定符&#xff1a; 使用using将命名空间中某个成员引入&#xff1a; 使用using namespace命名空间名称引用&#xff1a; C…

【c++】类和对象(四)深入了解拷贝构造函数

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好啊&#xff0c;本篇内容带大家深入了解拷贝构造函数 目录 1.拷贝构造函数1.1传值调用的无限调用1.2浅拷贝1.3深拷贝1.4深拷贝的实现 1.拷贝构造函数 拷贝构造函数是一种特殊的…

yolov5+pyside6+登录+用户管理目标检测可视化源码

一、软件简介 这是基于yolov5目标检测实现的源码&#xff0c;提供了用户登录功能界面&#xff1b; 用户需要输入正确的用户名和密码才可以登录。如果是超级管理员&#xff0c;可以修改普通用户的信息&#xff0c;并且在检测界面的右上角显示【管理用户】按钮。 支持图片、视频、…

程序员快速上手一门技术

1 明确需求 明确学这个技术的需求&#xff1a;如工作需求或职业发展 2 了解技术 2.1 这个技术是做什么&#xff1f; 2.2 这个技术的优缺点&#xff1f; 2.3 这个技术适用什么场景&#xff1f; 3 去官网文档查看技术 4 快速上手 4.1 快速学习增删改查&#xff0c;写出一…

访问二维数组本质

先从一维数组讲起 int main() {int arr[5] { 1,2,3,4,5 };for (int i 0; i < 5; i) {printf("%d",arr[i]); //对数组进行访问}return 0; } 其实 arr [ i ] * (arr i) 这两个是完全相等的&#xff0c;在c语言指针&#xff08;1&#xff09;8.数组名与 …

机器人深度学习IMU和图像数据实现焊接精细操作

在双电极气体保护金属弧焊 &#xff08;DE-GMAW&#xff09; 中&#xff0c;对焊枪和旁路电极位置的精确控制是至关重要的。为了这一过程&#xff0c;科研团队提出了安装微型惯性测量单元&#xff08;IMU&#xff09;传感器和摄像头&#xff0c;来记录焊工控制焊枪的移动和微调…

如何配置高质量的告警

运维工程师吐槽起告警问题&#xff0c;人人都是BBKing&#xff01; 每天应对花式告警问题&#xff0c; 无关紧要的、短时急剧爆发的 被疲劳告警淹没的重要告警 和每天崭新的太阳一样&#xff0c; 每次的告警也是独一无二的&#xff01; 想躺平&#xff0c;不可能 下一秒…

01背包(acwing闫氏DP分析法)

题目描述&#xff1a; 有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式&#xff1a…

MATLAB:微分方程(组)数值解

一、显式微分方程 clc,clear tspan [0:10]; y0 2; [t1,y1] ode23(odefun_1,tspan,y0); %求数值解&#xff0c;精度相对低 [t2,y2] ode113(odefun_1,tspan,y0); %求数值解&#xff0c;精度相对高 yt sqrt(tspan1)1; %求精确解 subplot(1,2,1) plot(t1,y1,bo,t2,y2,r*,tspa…

C语言:动态内存管理(malloc,calloc,realloc,free)

目录 前言 malloc函数 free函数 calloc函数 realloc函数 前言 在这一章节将讲解动态内存分配&#xff0c;它可以在程序的堆区创建一块内存&#xff0c;在这块内存中存什么值就是由自己决定的了 开辟的空间有两个特点&#xff1a; 1. 空间开辟的大小是固定的 2. 数组在…

视频 | 轨迹模型及其它潜变量模型理论与实践

2024年3月20日&#xff0c;郑老师开办了“春分”临床统计学沙龙&#xff0c;本期沙龙和诸位分享了轨迹增长模型&#xff0c;以及其它潜变量模型包括潜类别模型和潜剖面模型的详细介绍和文献解读&#xff0c;R语言代码实践也有分享&#xff01; 非常感谢各位朋友在忙碌的工作生活…

线性数据结构----(数组,链表,栈,队列,哈希表)

线性数据结构 数组链表栈使用场景 队列应用场景 哈希表特点哈希函数&#xff0c;哈希值&#xff0c;哈希冲突键值对 Entry 开放寻址法和拉链法 参考文档 数组 数组(Array) 是一种很常见的数据结构。由相同类型的元素组成&#xff0c;并且是使用一块连续的内存来存储的。 在数组…

安装redis时候修改过的配置文件

只要是石头&#xff0c;到哪里都不会发光的 bind 绑定主机某个网卡对应的IP地址&#xff0c;如果某个主机有两个网卡A和B&#xff0c;那么绑定了A&#xff0c;通过B连接就会无法访问protected-mode 保护模式 Yes为只能本地访问port 启动的端口号pidfile pid存放的位置&#xff…

python django实战开发序列化器的一个应用心得分享

需求: 查询的时候返回不包括SharePasswd 字段, 但是新增操作需要用到该字段 再不写多个model模型和序列化器的前提下实现 如果您在查询&#xff08;GET 请求&#xff09;时不希望返回 SharePasswd 字段&#xff0c;但在新增&#xff08;POST 请求&#xff09;时需要用到该字段…

Python3爬取2023省市区

爬取地址https://www.stats.gov.cn/sj/tjbz/tjyqhdmhcxhfdm/2023/ import re import requests import pandas as pd import warnings warnings.filterwarnings("ignore") import time from lxml import etree import pymysql t ,urls ,names [],[],[] INDEX_URL &…

Java两地经纬度通过高德api获取两地距离(公里)

代码如下&#xff1a; String startLongitude entity.getLONGITUDE(); // 起点&#xff08;当前位置&#xff09;经度String startLatitude entity.getLATITUDE(); // 起点纬度String endLongitude entity.getLO(); // 终点经度String endLatitude entity.getLA(); …

Spring框架介绍及详细使用

前言 本篇文章将会对spring框架做出一个比较详细的讲解&#xff0c;并且每个知识点基本都会有例子演示&#xff0c;详细记录下了我在学习Spring时所了解到全部知识点。 在了解是什么spring之前&#xff0c;我们要先知道spring框架在开发时&#xff0c;服务器端采用三层架构的方…

电子元器件批发采购的数字化转型与技术应用

电子元器件批发采购的数字化转型和技术应用是提高效率、优化供应链管理以及增强竞争力的关键。以下是一些数字化转型和技术应用的方面&#xff1a; 电子商务平台&#xff1a;建立并优化电子商务平台&#xff0c;提供在线采购功能&#xff0c;使客户能够方便地浏览产品、下订单、…