开始学习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. 初学Redis(1)——认识Redis

    Redis官网对Redis的定义是:“Redis is an open source, BSD licensed, advanced key-value cache and store”,可以看出,R ...

  2. 【原创】js实现一个可随意拖拽排序的菜单导航栏

    1.想做这个效果的原因主要是用在UC上看新闻发现他们的导航菜单很有趣.无聊的时候在哪划着玩了很久.所以就干脆自己写一个.原效果如下 2.整体效果如下,在已推荐和未添加里面每个小方块可以触摸移动位置互换 ...

  3. 自己总结SVN必知点

    1.只有添加或删除文件,才与xcodeproj文件有关 2.本地新建文件,为未知文件,符号为问号?,添加文件先add为A文件后,再commit         3.删除文件为叹号,右键删除为D,删除本 ...

  4. 2. iOS程序的生命周期

    程序启动-生命周期 来自:  QQ: 853740091 1.首先讲解UIApplication对象 (1)UIApplication对象是应用程序的象征,一个UIApplication对象就代表一个 ...

  5. jq表头固定

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta na ...

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

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

  7. Vue#组件

    组件: 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能. 使用: ...

  8. idapython在样本分析中的使用-字符解密

    最近接手的一个样本,样本中使用了大量的xor加密,由于本身样本不全,无法运行(好吧我最稀饭的动态调试没了,样本很有意思,以后有时间做票大的分析),这个时候就只好拜托idapython大法了(当然用id ...

  9. 摸索探寻之Mac OS 使用及快捷键

    刚发现的一个介绍Mac OS入门的帖子,新入手Mac的同学可以看看http://www.cnblogs.com/chijianqiang/archive/2011/08/03/2126593.html ...

  10. 在DrawingVisual上绘制圆形的进度条,类似于IOS系统风格。

    1.说明:在WPF中,文件下载时需要显示下载进度,由于系统自带的条型进度条比较占用空间,改用圆形的进度条,需要在DrawingVisual上呈现. 运行的效果如图: private Point Get ...