前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >IoC与DI的不同和它们分别的作用

IoC与DI的不同和它们分别的作用

原创
作者头像
可大可小
修改2021-03-11 17:54:37
6380
修改2021-03-11 17:54:37
举报

大多数人可能搞混这两个术语。可能是由于在Spring中大量使用了这些概念而导致的混乱,其中使用了Inversion of Control来启用依赖注入。

这篇文章旨在以一种简单的方式来解释这两种说法。 

控制反转

基本概念

IoC的非正式定义:“ IoC是当你让其他人为你创建对象时。” 因此 ,该对象不是由你的代码编写“ new MyObject”,而是由其他人创建的。此 “其他人” 通常称为IoC容器。

这个简单的解释说明了一些非常重要的想法:

  1. 之所以称为IoC,是因为对对象的控制被反转了,不是程序员,而是其他人控制对象。
  2. IoC是相对的,因为它只适用于应用程序的某些对象。所以有些对象可能有IoC,而有些对象则由程序员直接控制。

除了Spring之外,还有其他IoC示例,例如 Java Servlet 和 Akka Actors

细节

让我们进一步研究IoC的定义。IoC不仅仅是对象创建:Spring Context或Servlet容器不仅可以创建对象,而且可以管理对象的整个 生命周期。这包括创建对象,销毁它们以及在对象生命周期的不同阶段调用对象的某些方法。这些方法通常称为 回调。再次注意术语:容器调用的方法是回调,而不是 程序员对自己的代码进行的 直接调用

前面提到的所有IoC容器都实现某种生命周期:  Spring Bean生命周期,  Servlet生命周期和 Akka Actor生命周期

要考虑的另一件事是,尽管程序员放弃了对对象的控制,但是他们仍然需要定义 IoC容器用于创建所述对象的 模板

例如,在Spring中,类使用@Service 或 @Component进行注释 (还有许多其他注解 ),以表示Spring容器将管理这些类的实例(也可以使用XML配置代替注释)。Spring管理的对象称为Bean。

在Servlet应用程序中,任何实现Servlet 接口的类 都将由Servlet容器管理。

在Akka应用程序中,IoC容器称为 ActorSystem  ,托管对象是扩展特征Actor的类的实例,  并通过称为Props的配置对象创建 。

这是到目前为止讨论的想法的简要摘要:

  1. IoC容器控制和管理某些对象的生命周期:创建,销毁和回调调用。
  2. 程序员必须确定要由IoC容器管理其实例的类。有几种方法可以执行此操作:使用批注,通过扩展某些特定的类,使用外部配置。
  3. 程序员可以在一定程度上影响IoC容器管理对象的方式。通常,这是通过覆盖对象回调的默认行为来实现的。

Ioc容器

管理对象名称

管理对象定义

Spring Container

Bean

Classes defined with annotations/XML configuration

Servlet Container

Servlet

Classes implementing interface Servlet

Actor System

Actor

Classes extending trait Actor

到目前为止,我们已经解释了IoC,还没解释依赖注入(DI)。 

依赖注入

依赖注入已成为现代软件工程的基石之一,因为它是允许进行适当测试的基础。简而言之,拥有DI与拥有硬编码的依赖关系相反。

代码语言:java
复制
//硬编码
public class MyClass { 
    private MyDependency myDependency = new MyDependency(); 
}

//依赖注入
public class MyClass { 
    private MyDependency myDependency;

    public MyClass(MyDependency myDependency){
        this.myDependency = myDependency;
    }
}

依赖项可以通过几种方式注入,例如构造函数中的参数或通过“ set”方法。

与DI一样重要的是,它的使用也有一个缺点,即:依赖项的管理很不方便。举个个例子:MyClass1依赖于MyClass2,而MyClass3则取决于:

代码语言:java
复制
public class MyClass3 {
    public void doSomething(){}
}
代码语言:javascript
复制
//MyClass2 依赖 MyClass3
public class MyClass2 {
    private MyClass3 myClass3;

    public MyClass2(MyClass3 myClass3){
        this.myClass3 = myClass3;
    }

    public void doSomething(){
        myClass3.doSomething();
    }
}
代码语言:java
复制
//MyClass1 依赖on MyClass2
public class MyClass1 {
    private MyClass2 myClass2;

    public MyClass1(MyClass2 myClass2){
        this.myClass2 = myClass2;
    }

    public void doSomething(){
        myClass2.doSomething();
    }
}
代码语言:javascript
复制
public class Main {

    public static void main(String[] args) {

        //All dependencies need to be managed by the develope
        MyClass3 myClass3 = new MyClass3();
        MyClass2 myClass2 = new MyClass2(myClass3);
        MyClass1 myClass1 = new MyClass1(myClass2);

        myClass1.doSomething();
    }
}

现在,让我们假设更进一步,MyClass2需要一个新的依赖项:MyClass4。我们需要进行修改来解决这个新的依赖关系:

代码语言:javascript
复制
public class MyClass2 {
    private MyClass3 myClass3;
    private MyClass4 myClass4;

    public MyClass2(MyClass3 myClass3, MyClass4 myClass4){
        this.myClass3 = myClass3;
        this.myClass4 = myClass4;
    }

    public void doSomething(){
        myClass3.doSomething();
        myClass4.doSomething();
    }
}
代码语言:javascript
复制
public class Main {

    public static void main(String[] args) {

        MyClass4 myClass4 = new MyClass4();
        MyClass3 myClass3 = new MyClass3();
        MyClass2 myClass2 = new MyClass2(myClass3, myClass4);
        MyClass1 myClass1 = new MyClass1(myClass2);

        myClass1.doSomething();
    }
}

尽管这个例子中描述的情况还不错,但是现实应用程序可能在整个代码库中分散了几百个依赖项,就像上面的示例一样,它们的创建和管理将需要集中化。

控制反转和依赖注入一起发挥作用

我们刚刚讨论了在应用程序中管理数百个依赖关系的问题,其中可能包含非常复杂的依赖关系图。

因此,这就是IoC的主要作用。使用IoC,依赖项由容器管理,从而减轻了程序员的负担。

使用@Autowired之类的注释 ,要求容器在需要的地方注入依赖项,并且程序员不需要自己创建/管理这些依赖项。

代码语言:javascript
复制
public class MyClass1 {

    @Autowired
    private MyClass2 myClass2;

    public void doSomething(){
        myClass2.doSomething();
    }
}
代码语言:javascript
复制
public class MyClass2 {

    @Autowired
    private MyClass3 myClass3;
    @Autowired
    private MyClass4 myClass4;

    public void doSomething(){
        myClass3.doSomething();
        myClass4.doSomething();
    }
}

结论

我们已经将控制反转和依赖注入作为单独的概念进行了介绍,并说明了在某些情况下如何可以将这两个概念结合起来一起使用

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 控制反转
    • 基本概念
      • 细节
      • 依赖注入
      • 控制反转和依赖注入一起发挥作用
      • 结论
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档