控制反转与依赖注入详解

文章目录前言例子控制反转DI的方式构造函数注入set注入接口注入Service Locator学习资源前言前段时间看了Spring源码,有许多概念不是很清晰,所以看了一些资料,有不少收获,在此总结一下Inversion of Control Containers and the Dependency Injection pattern.这篇文章。目前java的轻量级容器非常流行,可以把不同项目的组件装配起来,进而成为一个独立的应用。而这些容器底层都是用同一种模式来进行组件的装配,也就是“IOC(Inv
摘要由CSDN通过智能技术生成

前言

前段时间看了Spring源码,有许多概念不是很清晰,所以看了一些资料,有不少收获,在此总结一下Inversion of Control Containers and the Dependency Injection pattern 这篇文章。

目前java的轻量级容器非常流行,可以把不同项目的组件装配起来,进而成为一个独立的应用。而这些容器底层都是用同一种模式来进行组件的装配,也就是“IOC(Inversion of Control/控制反转)”,更具体来说叫“DI(Dependency Injection/依赖注入)”。下文将主要对比IOC/DI和Service Locator(服务定位器)的不同之处,当然他们也有共同的作用:将组件的配置和使用分离

关键代码

有一个非常好用的电影查询组件。

 /**
 * 查询电影列表接口:findAll方法用于查询电影列表。
 */
public interface MovieFinder
{
   
    List findAll();
}
 
 /**
 * 查询电影列表实现类:用于适配不同的存储方式:txt、xml文件、数据库等。
 * 下面省略get set 构造方法。
 */
class MovieFinderImpl implements MovieFinder{
     
    public MovieFinderImpl(String filename)
    {
   
        this.filename = filename;
    }
    public List findAll(){
   
		//具体实现
	}
}

/**
* moviesDirectedBy可以根据电影导演名从列表中筛选电影。
* 控制反转的目的是让查询和存储解耦,下面省略get set 构造方法。
*/
class MovieLister{
     
  private MovieFinder finder;
  
  public MovieLister() {
   
    finder = new MovieFinderImpl("movies1.txt");
  }

  public Movie[] moviesDirectedBy(String arg) {
   
      List allMovies = finder.findAll();
      for (Iterator it = allMovies.iterator(); it.hasNext();) {
   
          Movie movie = (Movie) it.next();
          if (!movie.getDirector().equals(arg)) it.remove();
      }
      return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
  }
}

这个组件如果是个人使用,完全是没有问题的。但是如果其他人觉得好用,而他们的电影列表存储方式和我不同的话,就得重新提供一个 MovieFinder的实现类。所以说最终这个组件最终会有多个MovieFinder的实现类,而我们希望MovieLister类能够与MovieFinder的任何实现类配合工作,并且允许在运行期插入具体的实现类,插入动作完全脱离插件作者的控制。这里的问题就是:如何设计这个连接过程,使MovieLister类在不知道实现类细节的前提下与其实例协同工作。生产环境和测试环境可能会选择不同的部署方案,也就可能选择不同的接口实现类。这些新兴的轻量级荣日就是帮我们将这些插件组装成一个应用程序。这是这种新型轻量级容器面临的主要问题之一,并且普遍使用控制反转来实现。

控制反转

所以有一个问题:它们反转了哪方面的控制?来举两个例子对比一下吧:

1 普通方式:
早期的用户界面(控制台)完全由应用程序来控制的,你预先设计一系列命令,例如输入身高、输入体重等,应用程序逐条输出提示信息,并取回用户的响应,最后显示结果。

2 控制反转:
图形用户界面环境下,UI框架将负责执行一个主循环,你的应用程序只需为屏幕的各个区域提供事件处理函数即可。

看以看出图形用户界面下,程序的主控制权从程序移到了框架,也就是控制权发生了反转。 对于像Spring这样的轻量级容器,他的控制指的是确定接口的具体实现。 在上面那个demo中,MovieLister类负责确定MovieFinder的具体实现,然后MovieFinder也就不成其为一个插件了,因为它并不是在运行期插入应用程序中的。而这些轻量级容器则使用了更为灵活的办法,只要插件遵循一定的规则,一个独立的组装模块就能够将插件的具体实现注射到应用程序中。这个模式后来被称作"依赖注入"(Dependency Injection)。需要注意的是,为了消除程序和插件实现的依赖,除了DI还可以用ServiceLocater。

DI的方式

DI的思想简单来说就是有独立的类、装配类,装配类用于选择合适的接口实现,并填充对应的字段,如下图所示(引用的图):
在这里插入图片描述
下面将通过Spring举例三种依赖注入的方式,文件目录如下图,。
在这里插入图片描述

构造函数注入

xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="movieLister" class="MovieLister">
        <constructor-arg ref="movieFinder"/>   写法不唯一,这里不展开了
    </bean>
</beans>

测试

public class Application {
   
    public static void main(String[] args){
   
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml")
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛阳八中我最棒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值