关于Autofac的使用陷阱

说明:本文是对参考文章的一个整理,做一个记录,基本没有翻译,详情请参看原文.

使用注意要点:

Autofac will track every disposable component instance that it creates, no matter how that instance is requested.

Don’t resolve from the root container. Always resolve from and then release a lifetime scope.

不推荐、不宜的用法:

一、

interface IMyResource { … }

class MyResource : IMyResource, IDisposable { … }

When an instance of MyResource is created in an Autofac container, the container will hold a reference to it even when it is no longer being used by the rest of the program. This means that the garbage collector will be unable to reclaim the memory held by that component, so the following program will eventually exhaust all available memory and crash
var builder = new ContainerBuilder();
builder.RegisterType<MyResource>().As<IMyResource>();
using (var container = builder.Build())
{
    while (true)
        var r = container.Resolve<IMyResource>(); // Out of memory!
}
his is a far cry from typical CLR behaviour, which is one more reason why it is good to get away from thinking about an IoC container as a replacement for new. If we’d just created MyResource directly in the loop, there wouldn’t be any problem at all
while (true)
    var r = new MyResource(); // Fine, feed the GC

二、

interface IMyService { }

class MyComponent : IMyService
{
    // Dependency on a service provided by a disposable component
    public MyComponent(IMyResource resource) { … }
}

If a second component is resolved that depends on a service provided by a disposable component, the memory leak still occurs
while (true)
    // Still holds instances of MyResource
    var s = container.Resolve<IMyService>();

三、

interface IMyService2
{
    void Go();
}

class MyComponent2 : IMyService2
{
    Func<IMyResource> _resourceFactory;

    public MyComponent(Func<IMyResource> resourceFactory)
    {
        _resourceFactory = resourceFactory;
    }

    public void Go()
    {
        while (true)
            var r = _resourceFactory(); // Still out of memory.
    }
}

有什么方式可以改善上面的情况呢?

答:lifetime Scopes

// var container = …
while (true)
{
    using (var lifetimeScope = container.BeginLifetimeScope())
    {
        var r = lifetimeScope.Resolve<IMyResource>();
        // r, all of its dependencies and any other components
        // created indirectly will be released here
    }
}

Lifetime Scopes 可以被嵌套使用:

var ls1 = container.BeginLifetimeScope();
var ls2 = ls1.BeginLifetimeScope();
// ls1 is a child of the container, ls2 is a child of ls1

Lifetime Scopes 不会产生上下文依赖:

var ls1 = container.BeginLifetimeScope();
var ls2 = container.BeginLifetimeScope();
// ls1 and ls2 are completely independent of each other

Owned Instance:

Owned instances (Owned<T>) are the last tale in Autofac’s lifetime story.

An owned instance is a component that comes wrapped in its own lifetime scope. This makes it easier to keep track of how a component should be released, especially if it is used outside of a using statement.

To get an owned instance providing service T, you can resolve one directly from the container

var ownedService = container.Resolve<Owned<IMyService>>();

In lifetime terms, this is equivalent to creating a new lifetime scope from the container, and resolving IMyService from that. The only difference is that the IMyService and the lifetime scope that holds it come wrapped up together in a single object.

The service implementation is available through the Value property:

// Value is IMyService
ownedService.Value.DoSomething();

When the owned instance is no longer needed, it and all of its disposable dependencies can be released by disposing the Owned<T> object:

ownedService.Dispose();

Owner Instance 与 Fun 结合使用:

Components that are returned from Func<T> delegates are associated with the same lifetime scope as the delegate itself. If that component is itself contained in a lifetime scope, and it creates a finite number of instances through the delegate, then there’s no problem – everything will be cleaned up when the scope completes.

If the component calling the delegate is a long-lived one, then the instances returned from the delegate will need to be cleaned up eagerly. To do this, Owned<T> can be used as the return value of a factory delegate

class MyComponent2 : IMyService2
{
    Func<Owned<IMyResource>> _resourceFactory;

    public MyComponent(Func<Owned<IMyResource>> resourceFactory)
    {
        _resourceFactory = resourceFactory;
    }

    public void Go()
    {
        while (true)
            using (var r = _resourceFactory())
                // Use r.Value before disposing it
    }
}

Func<T> and Owned<T> can be combined with other relationship types to define relationships with a clearer intent than just taking a dependency on ILifetimeScope

参考文章:

http://nblumhardt.com/2011/01/an-autofac-lifetime-primer/

http://nblumhardt.com/2010/01/the-relationship-zoo/

时间: 2025-01-04 10:14:17

关于Autofac的使用陷阱的相关文章

深入理解Autofac生命周期

为什么Autofac表现的这样? 这里似乎有几个陷阱,虽然这里只有一个------并且这个值得重申: Autofac将会跟踪每一个他所创建的可销毁的组件实例,无论这个实例是怎样被获取的. 当然,最终.Autofac是非常谨慎地设计资源管理使得它比没有容器编程更简单. 注意我在这偷偷使用了资源这个词?我们谈论的内存溢出 什么是资源?

AutoFac Asp.Net Mvc

autofac依赖注入,帮我们实例化接口,无需使用传统的New 如: public class AutoFacController : Controller { public IPeople _people; public AutoFacController(IPeople people) { _people = people; } // GET: AutoFac public ActionResult Index() { ViewBag.test = _people.Getpeople();

java笔记--笔试中极容易出错的表达式的陷阱

我相信每一个学过java的人儿们都被java表达式虐过,各种"肯定是它,我不可能错!",然后各种"尼玛,真假,怎么可能?",虽然在实际开发中很少会真的让你去使用那些知识,但熟悉表达式的陷阱对于理解java数据类型在内存中的存储和运算以及JVM工作的原理有很大的帮助,最主要的,面试题太能考这些玩意了,有些坑当时爬出来了,过几天再做又会义无反顾的跳进去,于是我整理了自己做错过的一些题,也搜集了一些充满恶意的表达式方面的小题目,放在此处,警世: 问题 结果 脱坑必备 Sy

[转]依赖注入框架Autofac的简单使用

Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET,Unity,Castle等等所包含的,它很轻量级性能上也是很高的.于是,今天抽空研究了下它.下载地址:http://code.google.com/p/autofac/downloads/list 1)解压它的压缩包,主要看到Autofac.dll,Autofac.Configuration.dll,这也是本篇文章重点使用的Autofac的类库. 2)创建一个控制台工程,并且引用以上的DLL文件.创建一个数据库操作接

cocos2dx-3 addImageAsync陷阱

addImageAsync异步加载未响应回调前调用unbindImageAsync撤销消息回调void TextureCache::unbindImageAsync(const std::string& filename){    _imageInfoMutex.lock();    if (_imageInfoQueue && !_imageInfoQueue->empty())    {        std::string fullpath = FileUtils::g

当心商业智能的“陷阱”

当谈到有价值的,具有真实见解的评论,我总是可以指望每周五参加我#商业智能讨论#话题的参与者们.我最近开始小组讨论这个问题:“什么是商业智能系统的五大最差实践?” 那么让我们来看看为什么BI项目有时并不完全兑现其承诺.毕竟,失败是非常有益的. 这是我们编译的列表: 组织团体在BI项目中犯的一些最糟糕的错误 技术/工具: “认为BI工具将弥补对业务的不理解” “认为BI工具将代替BI解决业务问题” “为所有类型的用户提供通用的解决方案或工具——商业智能不是一个放之四海而皆准的通用的解决方案” “没有

Linux环境下线程消息同步的陷阱

我们程序中常常会使用到线程间的消息同步处理,比如以下一段伪码 var message = "": void func()  {   1. 启动线程Thread(该线程中填充message的内容):   2. 阻塞,直到等待到完成message填充的事件:   3. 处理message:   .... } void Thread()  {   1. 通过某种处理填充message:   2. 触发func中的阻塞事件: } 我们通常会使用条件变量来完成类似情况的线程同步处理 比如wind

读书笔记--C陷阱与缺陷(七)

第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一种判断编译器如何处理内存0的代码: 1 #include <stdio.h> 2 int main() 3 { 4 5 char *p; 6 p=NULL; 7 printf("location 0 contains: %d\n", *p); 8 9 return 0; 10

张书乐:逃离流量陷阱 好想你+百草味魔力联姻竟藏着这样的秘密

2016年7月,好想你以溢价近18倍的高彩礼联姻百草味,完成了"国内零食电商并购第一案".联姻一年的结果颇为令人惊讶,7月14日,好想你发布2017 年半年度业绩预告修正公告,预计实现归属于上市公司股东的净利润6520万元-6920万元,比上年同期增长:347.78%-375.25%. 文/张书乐(人民网.人民邮电报专栏作者) 新著有<微博运营完全自学手册> 于是乎,本来只是借助两家公司的名字凑合的联姻寓意"百年好合",开始变得清晰而真实. 到线下去,这