【JavaEE 进阶(三)】Spring IoCDI

server/2024/12/23 1:23:07/

❣博主主页: 33的博客❣
▶️文章专栏分类:JavaEE◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多进阶知识
在这里插入图片描述

目录

  • 1.前言
  • 2.Spring是什么?
  • 3.IOC&DI入门
  • 4.Ioc实现
    • 4.1@Controller
  • 4.2 @Service
    • 4.3@Repository
    • 4.4@Configuration
    • 4.5@Component
    • 4.6类注解区别
    • 4.7@Bean
  • 5.Bean的获取
    • 5.1通过类型获取
    • 5.2Bean的名称
    • 5.3通过名称获取
    • 5.4结果
  • 6.DI实现
    • 6.1属性注入
    • 6.2 构造方法注入
    • 6.3 Setter注入
    • 6.4三种注入优缺点
    • 6.5@Autowired问题
  • 7.总结

1.前言

本篇文章将介绍Spring IOC的概念和Spring DI的概念,以及 IOCDI的实现。

2.Spring是什么?

通过前⾯的学习,我们知道了Spring是⼀个开源框架,他让我们的开发更加简单.他⽀持⼴泛的应⽤场景,有着活跃⽽庞⼤的社区,这也是Spring能够⻓久不衰的原因.但是这个概念相对来说,还是⽐较抽象.我们⽤⼀句更具体的话来概括Spring,那就是**:Spring是包含了众多⼯具⽅法的IoC容器**

IOCDI_11">3.IOC&DI入门

IOC_12">3.1IOC

那么IOC是什么呢?IOC是Spring的一种思想,其实IoC我们在前⾯已经使⽤了,我们在前⾯讲到,在类上⾯添加@RestController 和@Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交给Spring管理,就是IoC思想。IOC(Inversion of Control (控制反转))就是把控制权交给Spring管理。
例如当我们设计汽车的时候,但汽车需要车身:

java"> public class NewCarExample {public static void main(String[] args) {Car car = new Car();car.run();}}
// 汽车对象static class Car {private Framework framework;public Car() {framework = new Framework();System.out.println("Car init....");}public void run(){System.out.println("Car run...");}}
//车身对象static class Framework {private String color;public Tire(){this. color= "red";System.out.println("颜色:" +color );}}}

但这样设计,如果我想修改颜色或者是构造方法,那么整个程序都会改动。那么我们就把创建子类的方式改为注入传递。

java"> public static void main(String[] args) {Framework framework = new Framework("blue");Car car = new Car(framework);car.run();}static class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init....");}public void run() {System.out.println("Car run...");}
}
static class Framework {private String color;public Framework(String color){this. color= color;System.out.println("颜色:" +color );}}}

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。

DI_72">3.2DI

DI: DependencyInjection(依赖注入)容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注入。程序运⾏时需要某个资源,此时容器就为其提供这个资源.
从这点来看, 依赖注入(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引入IoC容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。

DI_75">3.3IoC&DI使用

我们把Framework,和car交给Spring管理,那么我们只需要使用注解 :@Component,当需要使用的时候注入依赖,使用注解: @Autowired

java">public class CarController {@Autowiredprivate Car car;public CarController(){car.run;}
} 
//汽车@Componentstatic class Car {@Autowiredprivate Framework framework;public void run() {System.out.println("Car run...");}
}
//车身
@Component
static class Framework {private String color;public Framework() {this.color = "red";System.out.println("颜色:" + color);}public  Framework(String color){this. color= color;System.out.println("颜色:" +color );}}}

4.Ioc实现

类注解:@Controller、@Service、@Repository、@Component、@Configuration.
⽅法注解:@Bean.

4.1@Controller

java"> @Controller//一般用于注解controller
public class UserController {public void sayHi(){System.out.println("hi,UserController...");}}

4.2 @Service

java">@Service
public class UserService {public void doService(){System.out.println("do Service....");}
}

4.3@Repository

java">@Repository
public class UserRepository {public void doRespository(){System.out.println("do  Respository...");}
}

4.4@Configuration

java">@Configuration
public class UserConfiguration {public void doConfiguration(){System.out.println("do Configuration...");}
}

4.5@Component

java">public class UserComponent {public void doComponent(){System.out.println("do component...");}
}

4.6类注解区别

@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.
@Servie:业务逻辑层,处理具体的业务逻辑.
@Repository:数据访问层,也称为持久层.负责数据访问操作
@Configuration:配置层.处理项⽬中的⼀些配置信息
当我们去看源码时,会发现@Service、@Repository、@Configuration.中都包含@Component说明这些注解本身属于@Component的“子类”。
在这里插入图片描述
但@Controller注解比较特殊,当我们一个类中又url接口时,只能使用@Controller,其他四个一般清空下可以混用。

4.7@Bean

类注解是添加到某个类上的,但是存在两个问题:使⽤外部包⾥的类, 没办法添加类注解
⼀个类,需要多个对象,⽐如多个数据源这种场景, 我们就需要使⽤⽅法注解@Bean,在Spring框架的设计中,⽅法注解@Bean 要配合类注解才能将对象正常的存储到Spring容器中.

java">public class User {String name;public User(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}
java">@Configuration
public class UserInfo {@Beanpublic User user(){return new User("张三");}@Bean User user2(){return new User("李四");}
}

5.Bean的获取

5.1通过类型获取

既然已经把 UserController交给了Spring管理,那么如何获取呢?
从上下文对象中获取:

java">//获取Spring上下问对象ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio//根据类型获取对象UserController userController = context.getBean(UserController.class);//通过名字获取bean
UserController userController = (UserController) context.getBean("userController");
//通过类型+名字
UserController userController = (UserController) context.getBean("userController",UserController.class);
userController.sayHi();

5.2Bean的名称

除了通过类型获取,也可以通过名称获取,那么Bean的名称是说明呢?我们先来看一看官网的介绍:
在这里插入图片描述
类注解命名约定
1.bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写
例如:
类名:UserController, Bean的名称为:userController
类名:AccountManager,Bean的名称为: accountManager
2.有⼀些特殊情况,当有多个字符并且第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写
类名:UController, Bean的名称为:UController
类名:AManager,Bean的名称为: AManage
方法注解命名约定:
方法名就是bean的名称

5.3通过名称获取

java">ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
//通过名字获取bean
UserController userController = (UserController) context.getBean("userController");
//通过类型+名字
UserController userController = (UserController) context.getBean("userController",UserController.class);
userController.sayHi();

5.4结果

在这里插入图片描述
我们发现方法调用成功,但当我们打印引用地址的时候发现地址一样
在这里插入图片描述
那么就说明调用的是同一个对象,通过源码我们可以知道获取bean对象是父类BeanFactory提供的功能。
ApplicationContext VS BeanFactory(常⻅⾯试题)
继承关系和功能方面来说:Spring容器有两个顶级的接⼝:BeanFactory和
ApplicationContext。其中BeanFactory提供了基础的访问容器的能⼒,⽽
ApplicationContext 属于 BeanFactory 的⼦类,它除了继承了BeanFactory的所有功能之外,它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等方面的支持.
从性能方面来说:ApplicationContext是⼀次性加载并初始化所有的Bean对象,⽽BeanFactory 是需要那个才去加载那个,因此更加轻量。

DI_246">6.DI实现

上面我们讲解了IOC实现的具体内容,接下来讲DI事项的内容,DI其实就是一个依赖注入的过程,简单来说就是把对象取出来放在某个类的属性中。
Spring给我们提供了三种方式注入:

1.属性注⼊(FieldInjection)
2. 构造⽅法注⼊(ConstructorInjection)
3. Setter 注⼊(SetterInjection)

6.1属性注入

就是使用@Autowired 实现的,将Service类注⼊到Controller类中。 Service 类的实现代码如下:

java">@Controllerpublic class UserController { @Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}}

6.2 构造方法注入

java">@Controllerpublic class UserController2 {private UserService userService;@Autowiredpublic UserController2(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}}

注意
如果一个类只有一个构造方法,那么@Autowired 可以省略,如果一个类有多个构造方法默认使用无参的构造方法,那么此时需要添加@Autowired 来明确指定到底使⽤哪个构造⽅法。

6.3 Setter注入

java">@Controller
public class UserController3 {
private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController3...");userService.sayHi();}}

6.4三种注入优缺点

属性注⼊
优点:简洁,使⽤⽅便;
缺点:只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指针异常)
不能注⼊⼀个Final修饰的属性
构造函数注入(Spring4.X推荐)
优点:可以注⼊final修饰的属性
注⼊的对象不会被修改
依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法.
通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的
缺点:注入多个对象时,代码会⽐较繁琐
Setter注⼊(Spring3.X推荐)
优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊
缺点:不能注入⼀个Final修饰的属性
注⼊对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险.

6.5@Autowired问题

当一个类型存在多个对象时,使用@Autowired就会存在问题,例如:

java">@Configuration
public class UserInfo {@Beanpublic User user(){return new User("张三");}@Bean User user2(){return new User("李四");}
}
@Autowired
private User Uers;
public void sayhi(){System.out.println("hi,UserController");System.out.println(Uers);}

出现错误:
在这里插入图片描述
报错原因,非唯一的bean对象。那么如何解决呢?可以使用@Primary、@Qualifier、@Resource注解。
当有多个相同类型的对象时,用@Primary可以确定默认的实现:

java">@Configuration
public class UserInfo {@Bean@Primarypublic User user(){return new User("张三");}@Bean User user2(){return new User("李四");}
}

在这里插入图片描述
使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean的名称。
@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

java">@Autowired@Qualifier("user2")private User Uers;public void sayhi(){service.doService();System.out.println("hi,UserController");System.out.println(Uers);}

在这里插入图片描述
使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。

java">  @Resource(name = "user2")private User Uers;public void sayhi(){service.doService();System.out.println("hi,UserController");System.out.println(Uers);}

注入顺序:
在这里插入图片描述
@Autowired执行流程:

按照类型查找:
如果没有找到就抛出异常
如果查找到一个就直接插入,
如果找到多个就根据名称查找,找到就注入,没有找到就抛出异常

@Qualifier+@Autowired执行流程:

直接按照类型+名称查找
如果@Autowired对应的类型只有一个,但是名称和@Qualifier名称不一样,注入也是失败的

@Autowird与@Resource的区别
@Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
@Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊.相⽐于@Autowired 来说@Resource ⽀持更多的参数设置,例如name设置,根据名称获取Bean。

7.总结

Spring, Spring Boot和SpringMVC的关系以及区别
Spring: 简单来说,Spring是⼀个开发应⽤框架,什么样的框架呢,有这么⼏个标签:轻量级、⼀站式、模块化,其⽬的是⽤于简化企业级应⽤程序开发.
Spring的主要功能:管理对象,以及对象之间的依赖关系,⾯向切⾯编程,数据库事务管理,数据访问,web框架⽀持等.但是Spring具备⾼度可开放性,并不强制依赖Spring,开发者可以⾃由选择Spring的部分或者全部,Spring可以⽆缝继承第三⽅框架,⽐如数据访问框架(Hibernate、JPA),web框架(如Struts、JSF)
Spring MVC:SpringMVC是Spring的⼀个⼦框架,Spring诞⽣之后,⼤家觉得很好⽤,于是按照MVC模式设计了⼀个MVC框架(⼀些⽤Spring解耦的组件),主要⽤于开发WEB应⽤和⽹络接⼝,所以Spring MVC是⼀个Web框架. Spring MVC基于Spring进⾏开发的,天⽣的与Spring框架集成.可以让我们更简洁的进⾏Web层开发,⽀持灵活的URL到⻚⾯控制器的映射,提供了强⼤的约定⼤于配置的契约式编程⽀持,⾮常容易与其他视图框架集成,如Velocity、FreeMarker等。
Spring Boot: Spring Boot是对Spring的⼀个封装,为了简化Spring应⽤的开发⽽出现的,中⼩型企业,没有成本研究⾃⼰的框架,使⽤SpringBoot可以更加快速的搭建框架,降级开发成本,让开发⼈员更加专注于Spring应⽤的开发,⽽⽆需过多关注XML的配置和⼀些底层的实现。Spring Boot 是个脚⼿架,插拔式搭建项⽬,可以快速的集成其他框架进来.⽐如想使⽤SpringBoot开发Web项⽬,只需要引⼊SpringMVC框架即可,Web开发的⼯作是SpringMVC完成的,⽽不是SpringBoot,想完成数据访问,只需要引⼊Mybatis框架即可.Spring Boot只是辅助简化项⽬开发的,让开发变得更加简单,甚⾄不需要额外的web服务器,直接⽣成jar包执⾏即可.
最后⼀句话总结:SpringMVC和SpringBoot都属于Spring,SpringMVC是基于Spring的⼀个MVC框架,⽽SpringBoot是基于Spring的⼀套快速开发整合包

下期预告:Spring Boot配置文件


http://www.ppmy.cn/server/47420.html

相关文章

Spring Boot(七十七):SpringBoot实现接口内容协商功能

1 什么是内容协商 简单说就是服务提供方根据客户端所支持的格式来返回对应的报文,在 Spring 中,REST API 基本上都是以 json 格式进行返回,而如果需要一个接口即支持 json,又支持其他格式,开发和维护多套代码显然是不合理的,而 Spring 又恰好提供了该功能,那便是Conten…

【数据结构】链表----头结点的作用

链表是一种常见的数据结构,由一系列节点(Node)组成,每个节点包含数据和指向下一个节点的指针。链表的头结点(Head Node)也称为哨兵位,是链表的起点,通常有以下几个重要作用&#xff…

QT解析JSON格式超简单

目录 还是从最基础开始、什么是JSON 一、只解析json 1..解析JSON的主要类 2.主函数 二、解析并利用结构体存储 1.定义结构体 2.从 JSON 解析并填充结构体 实战示例 还是从最基础开始、什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数…

js 表格添加|删除一行交互

一、需求 二、实现 <div style"margin-bottom: 55px"><form action"" method"post" enctype"multipart/form-data" id"reportForm" name"sjf" style"margin-left: 25px;margin-bottom: 50px;&quo…

k8s练习--StorageClass详细解释与应用

文章目录 前言StorageClass是什么 一、实验目的配置过程 二、实验环境实验步骤一、配置网络存储NFS&#xff1a;1.主机基础配置2.配置 NFS: 二、开启rbac权限:三、创建nfs-deployment.yaml四、创建storageclass资源五、验证&#xff1a;1&#xff0e;创建PVC验证2.创建一个pod验…

go语言初学04

Go 语言近年来发展迅速&#xff0c;并且出现了许多优秀的开发框架和组件来支持各种不同的开发需求。以下是一些常用的 Go 语言开发框架和组件&#xff1a; Web 框架 Gin&#xff1a; URL: Gin简单、高效、易用&#xff0c;适合构建高性能的 Web 应用。 Echo&#xff1a; URL: …

Java中的大小顶堆的实现方式

在java中没有一个现成的大小顶堆的数据结构&#xff0c;但可以用PriorityQueue类代替。 PriorityQueue默认是升序的&#xff0c;因此可以模拟小顶堆最小值始终在队列的最前面&#xff0c;如果要模拟大顶堆&#xff0c;需要重新定义Comparator方法&#xff1a; PriorityQueue&l…

算法 | 刷题日记

1.递归通常是用栈来实现的 递归在其本质上是通过函数调用栈&#xff08;Call Stack&#xff09;来实现的&#xff0c;而不是队列&#xff08;Queue&#xff09;。当你调用一个函数时&#xff0c;该函数的局部变量、参数和返回地址会被压入&#xff08;push&#xff09;到一个由…