控制反转(IOC容器)-Autofac入门

注意:本文为原创文章,任何形式的转载、引用(包括但不限于以上形式)等,须先征得作者同意,否则一切后果自负。

简介

Autofac 是一个令人着迷的.NET IoC 容器。

它管理类之间的依赖关系。当应用程序的规模和复杂性随着时间不断增长时,也能易于更改。这是通过将常规 .NET 类视为组件来实现的。

入门

将 Autofac 集成到我们的应用程序的基本模式是:

  • 时刻牢记用控制反转(IOC)来构建我们的应用程序。
  • 添加Autofac引用。
  • 在应用程序启动时…

  • 创建一个ContainerBuilder。

  • 注册组件。
  • 构建容器并将其存储以备后用。
  • 在应用程序执行期间…

  • 从容器创建一个生命周期范围。

  • 使用生命周期范围来解析(resolve)组件的实例。

构建应用程序

控制反转背后的思想是:与其将应用程序中的类捆绑在一起,让类”新建”它们的依赖关系,不如在类构造期间把依赖项传递进来,如果每次传递的依赖项不相同,则可以随时切换依赖关系并调用相应的依赖项的实现。

对于我们的示例应用程序,我们将定义一个将当前时间写出的类。但是,我们不希望将它绑定到Console,因为我们希望能够稍后测试该类,或者在控制台不可用的地方使用它。

我们将尽可能地把写出时间的机制抽象化,因为如果我们以后想把它变成一个写出明天日期的程序版本,那么就可以快速实现该功能。

代码如下:

public interface IOutput
{
    void Write(string content);
}
public class Output : IOutput
{
    public void Write(string content)
    {
        Console.WriteLine(content);
    }
}
public interface ITodayWriter
{
    void WriteDate();
}
public class TodayWriter : ITodayWriter
{
    private IOutput _output;

    public TodayWriter(IOutput output)
    {
        _output = output;
    }

    public void WriteDate()
    {
        _output.Write(DateTime.Now.ToString());
    }
}

现在我们有了一个合理的结构化的依赖集,下面我们就把Autofac加入进来!

添加 Autofac 引用

第一步是将Autofac引用添加到我们的项目中。

对于我们的示例,仅使用核心Autofac包就够了,因为该包包含了我们所要使用的全部核心功能。

引入Autofac最简单的方法是通过NuGet。

控制反转(IOC容器)-Autofac入门

应用启动

在应用程序启动时,我们需要创建一个ContainerBuilder并在其中注册我们的组件。

组件可以是一个表达式、.NET类型或其他代码(该代码公开一个或多个服务,并可以接受其他依赖项)。

简单来说,考虑一个实现接口的 .NET 类型,像这样:

public class SomeType : IService
{
}

我们可以用以下两种方法来解决这个问题:

  • 作为类型本身,SomeType
  • 作为接口,IService

在这种情况下,组件是SomeType,它公开的服务是SomeType和IService(这一点你可能不太明白,不过没关系,后面我们将会讲解)。

在Autofac中,您可以使用以下内容进行注册ContainerBuilder:

// 创建一个构造器
var builder = new ContainerBuilder();

// 注册组件,并公开它的服务
builder.RegisterType<sometype>().As<iservice>();

// &#x5982;&#x679C;&#x4F60;&#x60F3;&#x628A;&#x7EC4;&#x4EF6;&#x81EA;&#x8EAB;&#x4E5F;&#x6CE8;&#x518C;&#x6210;&#x670D;&#x52A1;&#xFF0C;&#x90A3;&#x4E48;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;AsSelf()
builder.RegisterType<sometype>().AsSelf().As<iservice>();</iservice></sometype></iservice></sometype>

对于我们的示例程序,我们需要注册我们所有的组件(类)并公开它们的服务(接口),以便可以很好地连接起来。

我们还需要存储容器,方便以后用它来解析类型。

using System;
using Autofac;

namespace DemoApp
{
  public class Program
  {
    private static IContainer _Container { get; set; }

    static void Main(string[] args)
    {
      var builder = new ContainerBuilder();

      builder.RegisterType<output>().As<ioutput>();
      builder.RegisterType<todaywriter>().As<itodaywriter>();

      Container = builder.Build();

      //&#x8BE5;&#x65B9;&#x6CD5;&#x6211;&#x4EEC;&#x540E;&#x9762;&#x5B9E;&#x73B0;&#x5B83;
      WriteDate();
    }
  }
}</itodaywriter></todaywriter></ioutput></output>

现在我们有了一个容器 _,_其中所有组件都已注册,并且它们公开了适当的服务。让我们来使用它吧。

应用程序执行

在应用程序执行期间,我们需要使用我们注册的组件。我们可以通过生命周期范围解析它们来做到这一点。

容器本身就是一个生命周期范围,从技术上讲,我们可以直接从容器中解决问题。 但是,我非常不建议直接从容器解析

当我们解析一个组件时,根据我们定义的实例范围,会创建该对象的一个​​新实例。(解析一个组件大致相当于调用”new”来实例化一个类。这真的真的过于简单化了,但从类比的角度来看,这个比较很恰当。)一些组件可能需要被释放(就像它们实现了IDisposable一样)——Autofac可以在生命周期范围被释放时自动为我们处理那些组件的释放。

但是,容器在应用程序的整个生命周期内都存在。如果我们直接从容器中解决很多东西,等到最终,我们可能会有很多东西等待释放。这非常的不好(如果我们这样做,可能会发生”内存泄漏”的事故)。

相反,如果我们从容器创建一个子生命周期范围并从中解析。当我们完成组件解析后,Autofac会帮我们自动释放子作用域并为清理所有内容。

如果我们使用Autofac 集成库时,这个子作用域的创建主要是自动为我们完成的,因此我们不必考虑它。

对于我们的示例应用程序,现在我们将实现”WriteDate”方法,它从一个子生命周期范围获取写出结果,并在完成时自动处理该生命周期。

namespace DemoApp
{
  public class Program
  {
    private static IContainer Container { get; set; }

    static void Main(string[] args)
    {
      // &#x8BE5;&#x5185;&#x5BB9;&#x5728;&#x4E0A;&#x9762;&#x5DF2;&#x7ECF;&#x5B9E;&#x73B0;&#xFF0C;&#x4E0D;&#x518D;&#x91CD;&#x590D;
    }

    public static void WriteDate()
    {
      // &#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x5B50;&#x751F;&#x547D;&#x5468;&#x671F;&#x8303;&#x56F4;&#xFF0C;&#x89E3;&#x6790;ITodayWriter&#x670D;&#x52A1;&#xFF0C;&#x8C03;&#x7528;&#x65B9;&#x6CD5;&#xFF0C;&#x8C03;&#x7528;&#x7ED3;&#x675F;&#x540E;&#x88AB;&#x5B50;&#x751F;&#x547D;&#x5468;&#x671F;&#x8303;&#x56F4;&#x91CA;&#x653E;&#x6389;
      using (var scope = Container.BeginLifetimeScope())
      {
        var writer = scope.Resolve<itodaywriter>();
        writer.WriteDate();
      }
    }
  }
}</itodaywriter>

现在当我们运行程序时……

  • 该WriteDate方法创建了一个生命周期范围,从中可以解析依赖项。这样做是为了避免任何内存泄漏 – 如果ITodayWriter或其依赖项是一次性的,它们将在范围被释放时自动释放。
  • 该WriteDate方法从生命周期范围内手动解析ITodayWriter。(这里是”服务地点”。)在内部……

  • Autofac 看到ITodayWriter映射到TodayWriter,所以开始创建一个TodayWriter.

  • Autofac 认为在其构造函数中TodayWriter需要一个IOutput。(这是”构造函数注入”。)

  • Autofac 看到IOutput映射到Output,所以创建一个新Output实例。
  • Autofac 使用新Output实例来完成构建TodayWriter.

  • Autofac 返回完全构造的TodayWriter供WriteDate消费。

  • 对writer.WriteDate()的调用会转到全新的TodayWriter.WriteDate(),因为这是已解决的问题。
  • Autofac生命周期范围已释放。从该生命周期范围解析的任何一次性项也将被处理。

之后,如果我们想让我们的应用程序编写一个不同的日期,我们可以实现一个不同的ITodayWriter,然后在应用程序启动时更改注册。我们不需要更改任何其他类。这是不是非常的棒,这就是控制反转!

Original: https://www.cnblogs.com/iZOHC/p/14870523.html
Author: 张欧昊辰
Title: 控制反转(IOC容器)-Autofac入门

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/612737/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 分享一直在维护简单实用高效的C++Socket框架Swa-server(开源+源码)

    Swa-server 开源框架* 适用于中小型游戏,如:养成、RPG、棋牌等;应用软件,如:聊天室等* 已经封套好底层socket管理,sql请求处理、数据加密解密* 拿来即可开工…

    数据库 2023年6月14日
    093
  • java扫描某个包下的所有java类并加载

    最近在学习java的反射和注解,实际情景中需要扫描某个包下的所有java类,然后使用类加载器加载类。 基本思路,获得程序的路径扫描src下某个包内的子包和java类,实现也比较简单…

    数据库 2023年6月11日
    0106
  • 计算机操作系统(慕课版)思维导图

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据库 2023年6月16日
    099
  • Java面向对象(下)作业

    首先我把题目先列到这里,可以仔细看一下题。 (1)设计一个名为Geometric的几何图形的抽象类,该类包括: ①两个名为color、filled属性分别表示图形颜色和是否填充。 …

    数据库 2023年6月11日
    0142
  • 二叉树遍历的常用方法

    概述 二叉树的遍历可以说是解决二叉树问题的基础。我们常用的遍历方式无外乎就四种 &#x524D;&#x5E8F;&#x904D;&#x5386;、 …

    数据库 2023年6月11日
    085
  • rsync

    rsync rsync是linux系统下的数据镜像备份工具。使用快速增量备份工具Remote Sync可以远程同步,支持本地复制,或者与其他SSH、rsync主机同步。 rsync…

    数据库 2023年6月14日
    080
  • zabbix自定义监控进程和日志

    自定义监控 进程 日志 mysql主从状态 mysql主从延迟 自定义监控 进程 [root@client ~]# cd /usr/local/etc/ [root@client …

    数据库 2023年6月14日
    094
  • CompletableFuture方法全解

    public class SpringbootWebApplicationTests { private final Logger logger = LoggerFactory.g…

    数据库 2023年6月6日
    084
  • 3. 视图-触发器-存储过程-索引

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据库 2023年6月16日
    072
  • SQL的语法

    创建: create database [if not exists] 数据库名称 [default charset 字符集] [collate 排序规则]; (PS:方括号(&#…

    数据库 2023年6月16日
    086
  • Linux 学习笔记2(未完待续)

    Linux 学习笔记2 学习Linux的原因 Linux刚面世时并没有图形界面,所有操作全靠命令完成,如磁盘操作、文件读写、目录操作、进程管理、文件权限; 在职场中,大量的服务器维…

    数据库 2023年6月14日
    076
  • 不要让“Clean Code”更难维护,请使用“Rule of Three”

    当人们试图将”代码整洁之道(Clean Code)”的原则应用于现有的代码库时,我经常会问这个问题。 我认为这是合情合理的。 当我们开始重构遗留代码时,通常…

    数据库 2023年6月14日
    0104
  • leetcode 83. Remove Duplicates from Sorted List 删除排序链表中的重复元素(简单)

    一、题目大意 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 示例 1: 输入:head = [1,1,2]输出:[1,…

    数据库 2023年6月16日
    097
  • JDBC中常用的类和接口

    DriverManager类 DriverManager类 是JDBC的管理层,用来管理数据库中的 驱动程序。在使用Java操作数据库之前,必须使用 Class类 的 静态方法fo…

    数据库 2023年6月16日
    095
  • IO模型

    Unix IO模型 对于一个套接字上的输入操作,分为两步: 等待数据准备好(从网络中到达,到内核缓冲区) 将数据从内核缓冲区复制到应用进程缓冲区 I/O模型主要为以下五种: 阻塞I…

    数据库 2023年6月11日
    082
  • 数据库读写分离

    ———-数据库读写分离———- 环境准备:(两台虚拟机(centos7)可以连接外网 步骤1: 安装数据库,…

    数据库 2023年6月16日
    0114
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球