?个人主页: 中草药
?专栏:【Java】登神长阶 史诗般的Java成神之路
在 Java 开发的世界里,Spring 框架无疑是一颗璀璨的巨星,而其中的控制反转(Inversion of Control,简称 Ioc)和依赖注入(Dependency Injection,简称 DI)更是其核心特性之一。今天,就让我们一起深入探索 Spring 中的 Ioc 和 DI。
?一、IoC (Inversion of Control)
1、概念
Ioc,即控制反转(Inversion of Control),是一种重要的设计思想。
在传统的编程模式中,对象的创建和依赖关系的管理通常由程序员在代码中显式地进行。例如,一个对象 A 如果依赖于对象 B,那么在对象 A 的代码中就需要主动去创建对象 B。而在 Spring 的 Ioc 容器中,对象的创建和依赖关系的管理被反转了过来,不再由对象自身来管理,而是由容器来负责。
举例:
2、理解
需求:造一辆车
我们的实现思路:
先设计轮子(Tire),然后根据轮子的大小设计出底盘(Bottom),接着根据底盘设计出车身(Framework),最后根据车身设计好整个的汽车(Car),这里存在一个依赖关系
代码如下:
public class Car { private Framework framework; public Car(int size) { this.framework = new Framework(size); System.out.println("car init..."); } public void run() { System.out.println("car run..."); }}public class Framework { private Bottom bottom; public Framework(int size) { this.bottom = new Bottom(size); System.out.println("framework init..."); }}public class Bottom { private Tire tire; public Bottom(int size) { this.tire = new Tire(size); System.out.println("bottom init..."); }}public class Tire { private int size; public Tire(int size) { System.out.println("tire size:" + size); }}
当我们用IoC的思想去修改以上代码
如图,改进之后的控制权发生了翻转,不再是使用方创建并控制对象,而是把依赖对象注入到当前的对象,依赖对象的控制权不再由当前类控制
public 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..."); } } class Framework { private Bottom bottom; public Framework(Bottom bottom) { this.bottom = bottom; System.out.println("Framework init..."); } } class Bottom { private Tire tire; public Bottom(Tire tire) { this.tire = tire; System.out.println("Bottom init..."); } } class Tire { private int size; public Tire(int size) { this.size = size; System.out.println("轮胎尺寸:" + size); } }
3、优点
资源集中管理:LoC实现了资源的集中管理,实现资源的可配置和易管理松耦合:降低使用资源双方的依赖程度Spring就是一种IoC容器,帮助我们来进行资源管理
?二、DI(Dependency Injection)
1、概念
在软件开发中,当一个类(称为依赖类)需要使用另一个类(称为被依赖类)的功能时,传统的做法是在依赖类中直接创建被依赖类的实例。但这样会导致依赖类和被依赖类之间的耦合度较高,不利于代码的维护和扩展。
而依赖注入则是将被依赖类的实例通过外部方式(如构造函数、Setter 方法、字段注入等)注入到依赖类中,从而实现依赖类和被依赖类之间的解耦。
IoC是一种思想,DI相当于他的具体实现
2、实现方式
1.属性注入,主要通过@Autowired实现的,例如:
@Controller public class UserController { //注⼊⽅法1: 属性注⼊ @Autowired private UserService userService; public void sayHi(){ System.out.println("hi,UserController..."); userService.sayHi(); }}
2.构造方法注入:在依赖类中提供 Setter 方法,用于接收被依赖类的实例。例如
@Controllerpublic class UserController2 { //注⼊⽅法2: 构造⽅法 private UserService userService; @Autowired public UserController2(UserService userService) { this.userService = userService; } public void sayHi(){ System.out.println("hi,UserController2..."); userService.sayHi(); }}
3.Setter方法注入:使用注解等方式直接在依赖类的字段上注入被依赖类的实例。例如(在 Spring 框架中):
@Controllerpublic class UserController3 { //注⼊⽅法3: Setter⽅法注⼊ private UserService userService; @Autowired public void setUserService(UserService userService) { this.userService = userService; } public void sayHi(){ System.out.println("hi,UserController3..."); userService.sayHi(); }}
3、优缺点对比
~属性注入
优点:只能针对IoC容器,并且只有在使用时抛出NPE
缺点:不能注入一个Final修饰的属性
~构造函数注入(Spring 4.x推荐)
优点:
1. 可以注入Final修饰的属性
2.注入的对象不会被修改
3.依赖对象在使用之前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而
构造方法是在类加载阶段会执行的
4.通用性好,构造方法是JDK支持的,所以他适用于任何框架
缺点:注入多个对象,代码会比较繁琐
~Setter注入 (Spring 3.x推荐)
优点:方便在类实例之后,重新对该对象进行配置或者注入
缺点:不能注入Final修饰的属性,注入对象可能会被改变
4、@Autowired存在问题
如下代码,当同一类型出现多个Bean对象时,会报错:
@Componentpublic class BeanConfig { @Bean("u1") public User user1(){ User user = new User(); user.setName("zhangsan"); user.setAge(18); return user; } @Bean public User user2() { User user = new User(); user.setName("lisi"); user.setAge(19); return user; }}@Controllerpublic class UserController { @Autowired private UserService userService; //注入user @Autowired private User user; public void sayHi(){ System.out.println("hi,UserController..."); userService.sayHi(); System.out.println(user); }}
运行结果:
报错原因:非唯一的Bean对象
Spring提供了以下三种解决方案
1.@Primary
作用:当存在多个相同类型的 bean 可供注入时,使用@Primary
注解可以指定一个首选的 bean。如果没有其他更具体的限定条件,Spring 将优先选择被标记为@Primary
的 bean 进行注入。示例: // 定义两个相同类型的 bean @Component public class ServiceA implements MyService { //... } @Component @Primary public class ServiceB implements MyService { //... } @Component public class Consumer { @Autowired private MyService service; //... }
在上面的例子中,当Consumer
类需要注入MyService
类型的 bean 时,如果没有其他更具体的限定条件,Spring 会优先选择ServiceB
进行注入,因为它被标记为@Primary
。
2.@Qualifier
作用:当存在多个相同类型的 bean 时,可以使用@Qualifier
注解结合一个特定的名称来明确指定要注入的 bean。示例: @Component public class ServiceA implements MyService { //... } @Component public class ServiceB implements MyService { //... } @Component public class Consumer { @Autowired @Qualifier("serviceA") private MyService service; //... }
在这个例子中,通过@Qualifier("serviceA")
明确指定了要注入名为serviceA
的 bean,也就是ServiceA
类的实例。
3.@Resource
作用:@Resource
注解是 Java EE 规范中的注解,Spring 也支持该注解进行依赖注入。它可以通过名称或类型进行注入。如果只指定了名称,Spring 会根据名称查找 bean;如果没有指定名称,会根据类型进行注入。示例: @Component public class ServiceA implements MyService { //... } @Component public class ServiceB implements MyService { //... } @Component public class Consumer { @Resource(name = "serviceA") private MyService service; //... }
这里通过@Resource(name = "serviceA")
指定注入名为serviceA
的 bean,即ServiceA
类的实例。=
这些注解为解决多个相同类型的 bean 注入问题提供了灵活的方式,可以根据具体的需求选择合适的注解来确保正确的依赖注入。
5、@Autowired和@Resource的区别
@Autowired是spring框架提供的,@Resource是JDK提供的注解@Autowired默认是按类型注入的,而@Resource优先是按照名称注入的,@Resource提供更多的参数设置@Autowired的装配顺序
?三、Spring, Spring Boot 和Spring MVC的关系以及区别
1、Spring
简单而言是一个开发应用的框架---轻量级,一站式,模块化,母的是用于简化企业级应用程序的开发。 主要功能:管理对象,以及对象之间的依赖关系,面向切面编程,数据库事务管理,数据访问,web框架支持 具有高度可开放性,可以无缝继承第三方框架,不如数据访问框架(Hibernate,JPA),web框架(Status,JSF)2、Spring Boot
Spring Boot是对Spring的⼀个封装, 为了简化Spring应用的开发而出现的,中小型企业,没有成本研究自己的框架, 使用Spring Boot 可以更加快速的搭建框架, 降级开发成本, 让开发人员更加专注于Spring应用的开发,而无需过多关注XML的配置和⼀些底层的实现
Spring Boot 是个脚手架, 插拔式搭建项目, 可以快速的集成其他框架进来.
比如想使用SpringBoot开发Web项目, 只需要引入Spring MVC框架即可, Web开发的工作是SpringMVC完成的, 而不是SpringBoot, 想完成数据访问, 只需要引入Mybatis框架即可.
Spring Boot只是辅助简化项目开发的, 让开发变得更加简单, 甚至不需要额外的web服务器, 直接生成jar包执行即可.
3、Spring MVC
Spring MVC是Spring的一个子框架, Spring诞生之后, 大家觉得很好用, 于是按照MVC模式设计了一个 MVC框架(一些用Spring 解耦的组件), 主要用于开发WEB应用和网络接口,所以, Spring MVC 是⼀个Web框架
Spring MVC基于Spring进行开发的, 天生的与Spring框架集成. 可以让我们更简洁的进行Web层开发, 支持灵活的 URL 到页面控制器的映射, 提供了强大的约定大于配置的契约式编程支持, 非常容易与其他视图框架集成,如 Velocity、FreeMarker等
Spring MVC和Spring Boot都属于Spring,Spring MVC 是基于Spring的一个的MVC 框架,而Spring Boot 是基于Spring的⼀套快速开发整合包
欲望以提升热忱,毅力以磨平高山。
????????????????????????????
以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出?
制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢?