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