关于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/

你可能感兴趣的:(关于Autofac的使用陷阱)