开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻。随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring。本文不再介绍其背景与定义,比 如“究竟是什么控制被反转了?”、“注入了什么依赖?”等等问题,在网络上应该会搜出很多相关的内容。本文下面主要从入门者的角度来分析如下问题:“依赖 注入要解决什么问题?” 以及 “依赖注入可能是如何实现的?”

==============================

为了更好地解释这两个问题,本文列举了一个简单的代码小例子来配合说明,先将例子中设计的类列举如下:

比如我有苹果(Apple)、橘子(Orange)、香蕉(Banana)三种水果(Fruit),我想知道某种水果是什么颜色的。

对应水果类的实现代码非常简单:

Fruit是个接口:

package com.example.impl;

public interface Fruit {
//只有一个简单的方法:返回水果的颜色
public String getColor();
}

Apple、Banana、Orange三个类各自实现Fruit接口:

package com.example.action;
import com.example.impl.Fruit; public class Apple implements Fruit {
public String getColor() {
return "Red";
}
} --------------------------------------------
package com.example.action;
import com.example.impl.Fruit; public class Banana implements Fruit {
public String getColor() {
return "Yellow";
}
} --------------------------------------------
package com.example.action;
import com.example.impl.Fruit; public class Orange implements Fruit {
public String getColor() {
return "Orange";
}
}

==============================

OK,现在开始解释文章开头提出的两个问题:

(1)依赖注入要解决什么问题?

简单地说,依赖注入就是为了“对类之间的依赖进行解耦”。

比如上面的水果例子中,如果现在我想知道某种水果的颜色,我需要这样实现:

package com.example.test;
import com.example.impl.Fruit;
import com.example.action.*; public class Person {
public static void main(String[] args) {
//我想知道苹果的颜色.
Fruit fruit = new Apple();
System.out.println(fruit.getColor());
}
}

这里,我(Person)与水果类(这里具体为Apple)之间是有依赖的,即Person依赖Fruit,如果我现在想知道香蕉的颜色,那我只能修改Person类的代码如下:

package com.example.test;
import com.example.impl.Fruit;
import com.example.action.*; public class Person {
public static void main(String[] args) {
//我现在改成想知道香蕉的颜色了...
Fruit fruit = new Banana();
System.out.println(fruit.getColor());
}
}

这就是依赖产生的问题:我每次都必须修改Person的代码,才能实现“知道不同Fruit的颜色”的目的。

依赖注入要解决的就是上面这个问题,套在本例中就是:如果我想知道不同Fruit的颜色,我不需要修改Person的代码。也就是Person与Fruit解耦啦!!

那依赖注入具体是怎么实现的呢?且继续往下看。

(2)依赖注入可能是如何实现的?

之所以加“可能”二字,是因为我还没拜读过Spring的内部代码,所以暂时是靠自己的理解认为是这么实现的,但我估计应该八九不离十吧。

上面例子中说到,Person现在是对Fruit有依赖,Spring第一个想到的就是引入Java的反射机制,关于反射本文不再解释,直接拿过来用了,引入反射之后,Person的代码会变成这样:

package com.example.test;
import com.example.impl.Fruit;
import com.example.action.*; public class Person {
public static void main(String[] args) {
try {
//使用Java反射机制,使Person对Fruit具体类的依赖,转变为对类名的字符串的依赖...
Fruit fruit = (Fruit) Class.forName("com.example.action.Apple").newInstance(); //注意:forName()需要传入类的全路径名称
System.out.println(fruit.getColor());
}
catch (Exception e) {
System.out.println("class not found.");
}
}
}

代码看起来复杂了很多,但实际上只有标红的一行是最主要的变化,其余都是异常处理的代码。

可以看到,这个时候,Person对Fruit的依赖,已经转变成了对Fruit下面某个具体类的类名字符串的依赖了,即上面代码中,那段蓝色的字符串。如果此时我想知道橘子的颜色,我只需要把上面蓝色字符串的内容改成:com.example.action.Orange即可。

但是,现在Person还是没有完全摆脱对Fruit的依赖,只是依赖变成了一个字符串而已,那Spring第二个想到的就是通过文件读取这个类名字符串了,我们先在D盘建立一个test.txt文件,然后把“com.example.action.Apple”这段内容写到这个test.txt文件中,同时代码改为:

package com.example.test;
import com.example.impl.Fruit;
import com.example.action.*; public class Person {
public static void main(String[] args) {
try {
FileReader fr = new FileReader("D://test.txt");
BufferedReader br = new BufferedReader(fr);
String fruitName = br.readLine();
//使用Java反射机制,使Person对Fruit具体类的依赖,转变为对类名的字符串的依赖...
//加上读取文件的配置,类名字符串是从文件中读取的,不直接写在Person中
Fruit fruit = (Fruit) Class.forName(fruitName).newInstance(); //注意:forName()需要传入类的全路径名称
System.out.println(fruit.getColor()); br.close();
fr.close();
}
catch (Exception e) {
System.out.println("class not found.");
}
}
}

上面代码其实就是从D://test.txt中读取第一行内容,即类名字符串,然后利用java反射机制实例化这个类。

至此,可以看到Person类也不需要依赖Fruit的类名字符串了,转而变成了对D://test.txt这个文件的依赖,但是我们不需要修改这个文件的地址和文件名,只需要修改文件内容,就可以动态地知道不同水果的颜色了。比如我把test.txt的内容改成com.example.action.Banana,运行程序后,自然会打印出Yellow而不再是Red了。

而Spring实际上是把上文的txt文件替换成了xml文件,这样做的好处?xml文件中的标签更容易对类的各种属性进行表述,比如类名、类属性、类属性的值等等,不用像txt中那种没层次关系、需要自己瞎定义了。自然是更方便使用。

Spring实际使用时,大概就是把上面读取文件+反射的过程封装成ApplicationConext类,所以不需要在Person中写这么大段的代码了,而是直接用ApplicationContext和getBean()即可,或者直接用注解的方式更是方便,其实可以理解为Spring是把这些代码都封装到了框架里,不需要我们自己写了。

以上就是我在学习Spring依赖注入的过程中,一些自己的心得体会,希望大家多多交流、多提意见和建议!

浅析“依赖注入(DI)/控制反转(IOC)”的实现思路的更多相关文章

  1. 依赖注入 DI 控制反转 IOC MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下

    ADO.NET   一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data  → DataTable, ...

  3. 依赖注入 DI 控制反转 IOC 概念 案例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  4. ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下

    先简单了解一这个几个 名词的意思. 控制反转(IOC) 依赖注入(DI) 并不是某种技术. 而是一种思想.一种面向对象编程法则 什么是控制反转(IOC)?  什么是依赖注入(DI) 可以点击下面链接 ...

  5. ASP.NET中IOC容器Autofac(依赖注入DI 控制反转IOC)

    IOC的一个重点是在程序运行中,动态的向某个对象提供它所需要的其他对象.这一点是通过DI来实现的.Autofac则是比较流行的一款IOC容器. IoC和DI有什么关系呢?其实它们是同一个概念的不同角度 ...

  6. 轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI) 依赖注入和控制反转的理解,写的太好了。

    轻松学,浅析依赖倒置(DIP).控制反转(IOC)和依赖注入(DI) 2017年07月13日 22:04:39 frank909 阅读数:14269更多 所属专栏: Java 反射基础知识与实战   ...

  7. 浅谈(IOC)依赖注入与控制反转(DI)

    前言:参考了百度文献和https://www.cnblogs.com/liuqifeng/p/11077592.html以及http://www.cnblogs.com/leoo2sk/archive ...

  8. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->Spring Framework的依赖注入和控制反转

    Dependency Injection and Inversion of Control 1.概述: 1.1相关概念 bean:由IoC容器所管理的对象,也即各个类实例化所得对象都叫做bean 控制 ...

  9. 简单解析依赖注入(控制反转)在Spring中的应用

    IoC——Inversion of Control  控制反转DI——Dependency Injection   依赖注入 大家都知道,依赖注入是Spring中非常重要的一种设计模式.可能很多初学者 ...

随机推荐

  1. Spring Schedule 任务调度实现

    我们都知道任务调度可以用Quartz,但对于简单的定时任务,可以直接用Spring内置的Schedule来实现.可以由两种方式,注释+XML配置 注解方式: 注解也要先在sping.xml配置文件中配 ...

  2. JavaScript高级程序设计学习笔记--表单脚本

    提交表单 用户单击提交按钮或图像按钮时,就会提交表单.使用<input>和<button>都可以定义提交按钮,只要将其type特性的值设置为"submit" ...

  3. 删除安装的 cocoapods 的缓存方法

    清除 Cocoapods 本地缓存 特殊情况下,由于网络或者别的原因,通过 cocoapods 下载的文件可能会有问题.这时候可以删除 Cocoapods 的缓存(~/Library/Caches/C ...

  4. 创建新用户,连接Oracle数据库

    1.sys用户是最高管理员用户,那我们就用这个sys用户登录oracle:

  5. VR系统的分类

    转载请声明转载地址:http://www.cnblogs.com/Rodolfo/,违者必究. 根据用户参与和沉浸感的程度,通常把虚拟现实分为4大类:桌面虚拟现实系统.沉浸式虚拟现实系统.增强虚拟现实 ...

  6. Java中简单的操作(if语句、常用操作符、switch语句、变量赋值等)

    ---------------------if语句介绍--------------------------------------------------- class IfDemo { public ...

  7. Css Sprites 多张图片整合在一张图片上

    CSS Sprites原理: CSS Sprites其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的"background-image","backgro ...

  8. js特效2

    侧边栏简单版 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UT ...

  9. 【MongoDB初识】-安装篇

    1.首先MongoDB官网:http://www.mongodb.org,下载mongoDB 2.解压安装 自己安装在E:\mongdb 3.提示otfix KB2731284 or later up ...

  10. caffe中权值初始化方法

    首先说明:在caffe/include/caffe中的 filer.hpp文件中有它的源文件,如果想看,可以看看哦,反正我是不想看,代码细节吧,现在不想知道太多,有个宏观的idea就可以啦,如果想看代 ...