EasyNetQ笔记-替换IOC容器

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

        //registerServices:外部通过此参数注册服务
        public static IBus CreateBus(Func<IServiceResolver, ConnectionConfiguration> connectionConfigurationFactory, Action<IServiceRegister> registerServices)
        {
            var container = new DefaultServiceContainer();
            RegisterBus(container, connectionConfigurationFactory, registerServices);
            return container.Resolve<IBus>();
        }
            
        public static void RegisterBus(IServiceRegister serviceRegister,
                                       Func<IServiceResolver, ConnectionConfiguration> connectionConfigurationFactory,
                                       Action<IServiceRegister> registerServices)
        {
            serviceRegister.Register(c =>
            {
                var configuration = connectionConfigurationFactory(c);
                configuration.SetDefaultProperties();
                return configuration;
            });

            serviceRegister.RegisterDefaultServices();
            registerServices(serviceRegister);
        }
    public static class ServiceRegisterExtensions
    {
        /// <summary>
        ///     Registers the default EasyNetQ components
        /// </summary>
        /// <param name="serviceRegister">The register</param>
        public static void RegisterDefaultServices(this IServiceRegister serviceRegister)
        {
            Preconditions.CheckNotNull(serviceRegister, "container");

            // Note: IConnectionConfiguration gets registered when RabbitHutch.CreateBus(..) is run.
            // default service registration
            serviceRegister
                .Register<IConnectionStringParser, ConnectionStringParser>()
                .Register<ISerializer>(_ => new JsonSerializer())
                .Register<IConventions, Conventions>()
                .Register<IEventBus, EventBus>()
                .Register<ITypeNameSerializer, DefaultTypeNameSerializer>()
                .Register<ICorrelationIdGenerationStrategy, DefaultCorrelationIdGenerationStrategy>()
                .Register<IMessageSerializationStrategy, DefaultMessageSerializationStrategy>()
                .Register<IMessageDeliveryModeStrategy, MessageDeliveryModeStrategy>()
                .Register(new AdvancedBusEventHandlers())
                .Register<IProduceConsumeInterceptor, DefaultInterceptor>()
                .Register<IConsumerDispatcherFactory, ConsumerDispatcherFactory>()
                .Register<IExchangeDeclareStrategy, DefaultExchangeDeclareStrategy>()
                .Register<IConsumerErrorStrategy, DefaultConsumerErrorStrategy>()
                .Register<IErrorMessageSerializer, DefaultErrorMessageSerializer>()
                .Register<IHandlerRunner, HandlerRunner>()
                .Register<IInternalConsumerFactory, InternalConsumerFactory>()
                .Register<IConsumerFactory, ConsumerFactory>()
                .Register(c =>
                {
                    var connectionConfiguration = c.Resolve<ConnectionConfiguration>();
                    return ConnectionFactoryFactory.CreateConnectionFactory(connectionConfiguration);
                })
                .Register<IClientCommandDispatcher, SingleChannelClientCommandDispatcher>()
                .Register<IPersistentConnection, PersistentConnection>()
                .Register<IPersistentChannelFactory, PersistentChannelFactory>()
                .Register<IPublishConfirmationListener, PublishConfirmationListener>()
                .Register<IHandlerCollectionFactory, HandlerCollectionFactory>()
                .Register<IPullingConsumerFactory, PullingConsumerFactory>()
                .Register<IAdvancedBus, RabbitAdvancedBus>()
                .Register<IPubSub, DefaultPubSub>()
                .Register<IRpc, DefaultRpc>()
                .Register<ISendReceive, DefaultSendReceive>()
                .Register<IScheduler, ExternalScheduler>()
                .Register<IBus, RabbitBus>();
        }
}

但是如果您希望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();
原文地址:https://www.cnblogs.com/fanfan-90/p/13622335.html