26、Using Alternative DI Containers 替换DI容器

EasyNetQ是由独立组件的集合组成的。在内部,它使用了一个称为DefaultServiceProvider的微型内部DI(IoC)容器(EasyNetQ作者自己写的一个)。如果你看一下静态RabbitHutch类的代码(你用来创建IBus实例的那个),您将看到它只是创建了一个新的DefaultServiceProvider实例,注册所有EasyNetQ的组件,然后调用容器的Resolve() 方法,使用容器提供的依赖关系树创建一个IBus的新实例:

public static IBus CreateBus(IConnectionConfiguration connectionConfiguration, Action<IServiceRegister> registerServices)
{
    Preconditions.CheckNotNull(connectionConfiguration, "connectionConfiguration");
    Preconditions.CheckNotNull(registerServices, "registerServices");

    var container = createContainerInternal();
    if (container == null)
    {
        throw new EasyNetQException("Could not create container. " + 
            "Have you called SetContainerFactory(...) with a function that returns null?");
    }

    registerServices(container);
    container.Register(_ => connectionConfiguration);
    ComponentRegistration.RegisterServices(container);

    return container.Resolve<IBus>();  //从容器中拿出IBus的实例
}

但是如果您希望EasyNetQ使用您的选择容器呢?从版本0.25,RabbitHutch类提供了一个静态方法SetContainerFactory,它允许您注册一个可选的容器工厂方法,你想怎么实现EasyNetQ.IContainer接口都可以,只要通过该工厂方法提供给EasyNetQ即可。

Jeff Doolittle已经为Windsor and Structure Map创造了IoC容器封装:

https://github.com/jeffdoolittle/EasyNetQ.DI

在这个例子中,我们使用了Castle Windsor IoC容器:

// 注册我们替换的容器工厂
RabbitHutch.SetContainerFactory(() =>
    {
        // 创建一个Windsor IoC容器实例
        var windsorContainer = new WindsorContainer();

        // 把Windsor封装到我们写的实现了EasyNetQ.IContainer接口的封装类对象中
        return new WindsorContainerWrapper(windsorContainer);
    });

// 现在我们创建一个IBus接口的实例,但这次它是从windsor IoC容器中解析出来的,
// 而不是像以前例子那样,从EasyNetQ默认的IoC容器了。
var bus = RabbitHutch.CreateBus("host=localhost");

 

下面是WindsorContainerWrapper类,我用来封装Windsor IoC容器的实例的,目的是实现EasyNetQ.IContainer接口,因为EasyNetQ里访问容器都是用的这个接口类型的实例(当然你也可以自己去写一个封装,爱封装啥IoC就去封装啥):

public class WindsorContainerWrapper : IContainer, IDisposable
{
    private readonly IWindsorContainer windsorContainer;

    public WindsorContainerWrapper(IWindsorContainer windsorContainer)
    {
        this.windsorContainer = windsorContainer;
    }

    public TService Resolve<TService>() where TService : class
    {//解析组件
        return windsorContainer.Resolve<TService>();
    }

    public IServiceRegister Register<TService>(System.Func<IServiceProvider, TService> serviceCreator) 
        where TService : class
    {//注册组件
        windsorContainer.Register(
            Component.For<TService>().UsingFactoryMethod(() => serviceCreator(this)).LifeStyle.Singleton
            );
        return this;
    }

    public IServiceRegister Register<TService, TImplementation>() 
        where TService : class 
        where TImplementation : class, TService
    {
        windsorContainer.Register(
            Component.For<TService>().ImplementedBy<TImplementation>().LifeStyle.Singleton
            );
        return this;
    }

    public void Dispose()
    {
        windsorContainer.Dispose();
    }
}

 

注意在我的封装中,所有EasyNetQ服务都注册为singletons单例了。

 

恰当地清理Windsor很重要。EasyNetQ没有在IContainer上定义Dispose 方法,但是您可以通过Advanced Bus访问容器,这样清理Windsor:

((WindsorContainerWrapper)bus.Advanced.Container).Dispose();
bus.Dispose();

 

 

完。

posted on 2017-12-08 11:11  困兽斗  阅读(203)  评论(0编辑  收藏  举报

导航