Java Spring 控制反转(IOC)容器详解


Posted in Java/Android onOctober 05, 2021

IoC 容器是 Spring 的核心,也可以称为 Spring 容器。Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期。

Spring 中使用的对象都由 IoC 容器管理,不需要我们手动使用 new 运算符创建对象。由 IoC 容器管理的对象称为 Spring Bean,Spring Bean 就是 Java 对象,和使用 new 运算符创建的对象没有区别。

Spring 通过读取 XML 或 Java 注解中的信息来获取哪些对象需要实例化。

Spring 提供 2 种不同类型的 IoC 容器,即 BeanFactory 和 ApplicationContext 容器。

什么是容器?

容器是一种为某种特定组件的运行提供必要支持的一个软件环境。例如,Tomcat就是一个Servlet容器,它可以为Servlet的运行提供运行环境。类似Docker这样的软件也是一个容器,它提供了必要的Linux环境以便运行一个特定的Linux进程。

通常来说,使用容器运行组件,除了提供一个组件运行环境之外,容器还提供了许多底层服务。例如,Servlet容器底层实现了TCP连接,解析HTTP协议等非常复杂的服务,如果没有容器来提供这些服务,我们就无法编写像Servlet这样代码简单,功能强大的组件。早期的JavaEE服务器提供的EJB容器最重要的功能就是通过声明式事务服务,使得EJB组件的开发人员不必自己编写冗长的事务处理代码,所以极大地简化了事务处理。

无侵入容器

在设计上,Spring的IoC容器是一个高度可扩展的无侵入容器。所谓无侵入,是指应用程序的组件无需实现Spring的特定接口,或者说,组件根本不知道自己在Spring的容器中运行。这种无侵入的设计有以下好处:

1.应用程序组件既可以在Spring的IoC容器中运行,也可以自己编写代码自行组装配置;

2.测试的时候并不依赖Spring容器,可单独进行测试,大大提高了开发效率。

IOC控制反转

Spring提供的容器又称为IoC容器,什么是IoC?

Ioc—Inversion of Control,即“控制反转”,不是什么技术,是一个概念,是一种思想。指将传统上由程序代 码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的装配和管理。通俗点讲,将对象的创建权交给spring,我们需要new对象,则由spring帮我们创建,然后供我们使用。

那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。IoC的实质是如何管理对象,传统意义上我们使用new方式来创建对象,但在企业应用开发的过程中,大量的对象创建都在程序中维护很容易造成资源浪费,并且不利于程序的扩展。

其实现方式多种多样。当前比较流行的实现方式是依赖 注入。应用广泛。

依赖:classA 类中含有 classB 的实例,在 classA 中调用 classB 的方法完成功能,即 classA 对 classB 有依赖。

IOC理论推导

传统应用程序开发的弊端

在理解IoC之前,我们先看看通常的Java组件是如何协作的。

我们先用我们原来的方式写一段代码 .

1、先写一个UserDao接口

Java Spring 控制反转(IOC)容器详解

2、再去写Dao的实现类

public class UserDaoOneImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("One获取用户数据");
  }
}

3、然后去写UserService的接口

Java Spring 控制反转(IOC)容器详解

4、最后写Service的实现类

Java Spring 控制反转(IOC)容器详解

5、测试一下

Java Spring 控制反转(IOC)容器详解

6、再回到UserDao接口

Java Spring 控制反转(IOC)容器详解

把Userdao的实现类增加一个 .

public class UserDaoMyTwoImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Two获取用户数据");
  }
}

7、我们就需要去service实现类里面修改对应的实现

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoTwo();
   @Override
   public void getUser() {
       userDao.getUser();
  }
}

在假设, 我们再增加一个Userdao的实现类 .

public class UserDaoThreeImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Three获取用户数据");
  }
}

那么我们要使用Three , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .

“注入”机制

注入应用程序某个对象,应用程序依赖的对象

依赖注入可以通过set()方法实现。但依赖注入也可以通过构造方法实现。Spring的IoC容器同时支持属性注入和构造方法注入,并允许混合使用。

我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .

Java Spring 控制反转(IOC)容器详解

@Test
public void test(){
   UserServiceImpl service = new UserServiceImpl();
   service.setUserDao( new UserDaoTwoImpl() );
   service.getUser();
   //那我们现在又想添加Three去实现呢
   service.setUserDao( new UserDaoThreeImpl() );
   service.getUser();
}

以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

小结

传统程序设计如图,都是主动去创建相关对象然后再组合起来:

Java Spring 控制反转(IOC)容器详解

没有什么是加一层解决不了的

Java Spring 控制反转(IOC)容器详解

当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了

IOC本质

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

Java Spring 控制反转(IOC)容器详解

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

DI(依赖注入)

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。 比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注三水点靠木的更多内容!

Java/Android 相关文章推荐
教你用Java Swing实现自助取款机系统
Jun 11 Java/Android
SpringBoot+VUE实现数据表格的实战
Aug 02 Java/Android
java调用Restful接口的三种方法
Aug 23 Java/Android
springboot 多数据源配置不生效遇到的坑及解决
Nov 17 Java/Android
Jpa Specification如何实现and和or同时使用查询
Nov 23 Java/Android
关于ObjectUtils.isEmpty() 和 null 的区别
Feb 28 Java/Android
Java实现二分搜索树的示例代码
Mar 17 Java/Android
零基础学java之带参数以及返回值的方法
Apr 10 Java/Android
引用计数法和root搜索算法以及JVM中判定对象需要回收的方法
Apr 19 Java/Android
Spring Boot 的创建和运行示例代码详解
Jul 23 Java/Android
基于Android10渲染Surface的创建过程
Aug 14 Java/Android
Java中的Kafka为什么性能这么快及4大核心详析
Sep 23 Java/Android
Java spring定时任务详解
JAVA API 实用类 String详解
Oct 05 #Java/Android
SpringCloud之@FeignClient()注解的使用方式
Sep 25 #Java/Android
springboot中rabbitmq实现消息可靠性机制详解
Sep 25 #Java/Android
Spring Cloud 中@FeignClient注解中的contextId属性详解
Sep 25 #Java/Android
关于springboot配置druid数据源不生效问题(踩坑记)
Sep 25 #Java/Android
Java使用Unsafe类的示例详解
Sep 25 #Java/Android
You might like
php输出echo、print、print_r、printf、sprintf、var_dump的区别比较
2013/06/21 PHP
php Imagick获取图片RGB颜色值
2014/07/28 PHP
百度地图API使用方法详解
2015/08/25 PHP
利用php生成验证码
2017/02/23 PHP
总结PHP内存释放以及垃圾回收
2018/03/29 PHP
jquery 通过name快速取值示例
2014/01/24 Javascript
jQuery实现鼠标悬停显示提示信息窗口的方法
2015/04/30 Javascript
javascript中类的定义方式详解(四种方式)
2015/12/22 Javascript
js输入框使用正则表达式校验输入内容的实例
2017/02/12 Javascript
jQuery ajax请求struts action实现异步刷新
2017/04/19 jQuery
Js利用Canvas实现图片压缩功能
2017/09/13 Javascript
利用vue + element实现表格分页和前端搜索的方法
2017/12/25 Javascript
Linux Centos7.2下安装nodejs&npm配置全局路径的教程
2018/05/15 NodeJs
Vue2实时监听表单变化的示例讲解
2018/08/30 Javascript
浅谈VUE-CLI脚手架热更新太慢的原因和解决方法
2018/09/28 Javascript
微信小程序引用iconfont图标的方法
2018/10/22 Javascript
node.js中npm包管理工具用法分析
2020/02/14 Javascript
python下函数参数的传递(参数带星号的说明)
2010/09/19 Python
python解决字典中的值是列表问题的方法
2013/03/04 Python
Python迭代器和生成器介绍
2015/03/06 Python
Python中的多行注释文档编写风格汇总
2016/06/16 Python
python修改FTP服务器上的文件名
2019/09/11 Python
PyTorch实现AlexNet示例
2020/01/14 Python
python中os包的用法
2020/06/01 Python
详解python中的三种命令行模块(sys.argv,argparse,click)
2020/12/15 Python
python基于openpyxl生成excel文件
2020/12/23 Python
pycharm 快速解决python代码冲突的问题
2021/01/15 Python
老板电器官方购物商城:老板油烟机、燃气灶、消毒柜、电烤箱
2018/05/30 全球购物
乡镇党的群众路线教育实践活动个人整改方案
2014/10/31 职场文书
学校中秋节活动总结
2015/03/23 职场文书
唐山大地震的观后感
2015/06/05 职场文书
2015年街道办事处团委工作总结
2015/10/14 职场文书
交通安全教育心得体会
2016/01/15 职场文书
Nginx开启Brotli压缩算法实现过程详解
2021/03/31 Servers
基于Python绘制子图及子图刻度的变换等的问题
2021/05/23 Python
DIY胆机必读:各国电子管评价
2022/04/06 无线电