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();