从IoC开始说起

博主最早开始用的IoC容器叫AutoFac,那时候用它主要是为了生命周期管理——将EF上下文的生命周期限定为每请求。当然也总是每每听到IoC的好处,但是仍然不能理解其优势。最近在学习和实现Cqrs的时候,却是有了明显的体会了。我们以前分层的时候,用的Service和Reponsitory。通常的情形是:Service需要访问一些数据,就得在Reponsitory中添加一些方法,否则无法完成。往往这是很困惑的,Service经常成了Reponsitory的简单的包装。同时,Service是依赖于Reponsitory的,仓储提供了什么,服务才能继续做什么。同时——模型是被仓储引用的,也就是模型不是和Service紧密关联的。我们也尝试过将仓储和服务提取为接口,然而并没有直观的改善——因为我们依赖关系没有变(仓储接口<-仓储<-服务接口<-服务)。学习CQRS的时候,曾经看过一些例子,模型是和业务紧密结合的。当时博主用自己的依赖关系代入进去发现行不通。细看才发现,仓储的接口是和服务定义在一起的(因为只有服务会/允许调用这个)。仓储的实现引用了服务,实现了仓储接口。这个时候,情形变为了:服务去要求仓储实现这些方法。依赖关系为:(模型<-仓储接口<-服务)<-仓储实现。这里引出的问题是,服务本身是不清楚具体实现是哪个的,需要调用方来指定,IoC容器就起了这个作用,通过注册,可以为特定的接口指派特定的实现。

时过境迁,由于总总原因,博主现在开始使用Unity作为容器了。

仓储与QueryEntry

就博主目前对CQRS的理解而言,实现CQRS的一个目标是从架构上将数据的查询和提交分离。所以引入了一个QueryEntry,查询入口。查询入口也需要仓储支持,且具有更多的灵活性,比如对于SQL而言,直接提交SQL查询以改善联查性能。为了实现好的隔离性,查询入口也通过接口定义。在目前的处理中,QueryEntry和Reponsitory的接口放在同一层(领域层),其实现放在同一层(Storage层)。这样,如果针对SQL,那么特殊的查询使用SQL语句完成,如果针对Oracle就使用Oracle的查询语句完成。而任何实现了这些接口的DLL都可以替换原有的DLL,领域层就不关心持久化的事情了。

其实也考虑过QueryEntry直接使用实现类来处理,但是这样的话,仓储就要暴露给应用程序层(web)。

配置

在整个解决方案中,博主使用一个Configuration项目来配置各个组件(实现)的关系,这好比是前面博文中的Configuration类的放大。为了独立管理配置,所以引入了一个扩展类,将Unity的各种配置按照语义具体化。

    public class ComponentContainer
{
protected UnityContainer Container = new UnityContainer(); public UnityContainer GetContainer()
{
return Container;
} //public static ComponentContainer Config()
//{
// return new ComponentContainer();
//} public T Construct<T>()
{
return Container.Resolve<T>();
} public T Construct<T>(Type registedType)
{
return (T) Container.Resolve(registedType);
} public void Use<T, TI>(LifetimeManager manager = null) where TI : T
{
if (manager == null)
{
Container.RegisterType<T, TI>();
}
else
{
Container.RegisterType<T, TI>(manager);
}
} public void Use<T>(Type iType, LifetimeManager manager = null)
{
if (manager == null)
{
Container.RegisterType(typeof (T), iType);
}
else
{
Container.RegisterType(typeof(T), iType, manager);
}
} public void Use(Type type, Type iType, LifetimeManager manager = null)
{
if (manager == null)
{
Container.RegisterType(type, iType);
}
else
{
Container.RegisterType(type, iType, manager);
}
} public void UseInstance<T, TI>() where TI : T, new()
{
var instance = new TI();
Container.RegisterInstance(typeof (T), instance);
} public void SpecifyLifeTime<T>(LifetimeManager manager = null)
{
SpecifyLifeTime(typeof (T), manager);
} public void SpecifyLifeTime(Type type, LifetimeManager manager = null)
{
if (manager == null)
{
Container.RegisterType(type);
}
else
{
Container.RegisterType(type);
}
}
}

ComponentContainer

总的来数,Unity会被解决方案中的所有项目引用。而在所有的组件中,有以下几个需要通过IoC配置:ICommandBus(单例),IEventBus(单例),仓储,QueryEntry(查询入口)...,在CQRS层的Configuration名称空间下添加以下接口表示配置支持:

 public interface ICommandHandlerRegister
{
void RegisterCommandHandlers(ComponentContainer container);
} public interface IEventHandlerRegister
{
void RegisterEventHandlers(ComponentContainer container);
} public interface IQueryEntryRegister
{
void RegisterQueryEntries(ComponentContainer container);
} public interface IStorageRegister
{
void RegisterReponsitories(ComponentContainer container);
/*在这里完成工作单元的映射*/
void RegisterUnitOfWork(ComponentContainer container);
}
/*为流畅接口定义的扩展,配置语义化*/

    public static class FluentConfiguration
{
public static CqrsConfigurationResolver ConfigLifetimeManager<T>(this CqrsConfigurationResolver resolver, LifetimeManager manager)
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.SpecifyLifeTime(typeof (T), manager);
return resolver;
} public static CqrsConfigurationResolver UseEventBus<T>(this CqrsConfigurationResolver resolver) where T : IEventBus
{
if (resolver == null)
throw new ArgumentNullException("resolver");
/*生命周期与容器的生命周期保持一致,故而实现了单例*/
resolver.Use<IEventBus, T>(new ContainerControlledLifetimeManager());
return resolver;
} public static CqrsConfigurationResolver UseCommandBus<T>(this CqrsConfigurationResolver resolver) where T : ICommandBus
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<ICommandBus, T>(new ContainerControlledLifetimeManager());
return resolver;
} public static CqrsConfigurationResolver UseEventHandlerProvider<T>(this CqrsConfigurationResolver resolver)
where T : IEventHandlerProvider
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<IEventHandlerProvider, T>(new ContainerControlledLifetimeManager());
return resolver;
} public static CqrsConfigurationResolver UseCommandHandlerProvider<T>(this CqrsConfigurationResolver resolver)
where T : ICommandHandlerProvider
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<ICommandHandlerProvider, T>(new ContainerControlledLifetimeManager());
return resolver;
} public static CqrsConfigurationResolver UseStorageRegister<T>(this CqrsConfigurationResolver resolver)
where T : IStorageRegister, new()
{
if (resolver == null)
throw new ArgumentNullException("resolver");
var register = new T();
register.RegisterReponsitories(CqrsConfigurationResolver.Config);
register.RegisterUnitOfWork(CqrsConfigurationResolver.Config);
return resolver;
} public static CqrsConfigurationResolver UseCommandHandlerRegister<T>(this CqrsConfigurationResolver resolver)
where T : ICommandHandlerRegister, new()
{
if (resolver == null)
throw new ArgumentNullException("resolver");
var register = new T();
register.RegisterCommandHandlers(CqrsConfigurationResolver.Config);
return resolver;
} public static CqrsConfigurationResolver UseEventHandlerRegister<T>(this CqrsConfigurationResolver resolver)
where T : IEventHandlerRegister, new()
{
if (resolver == null)
throw new ArgumentNullException("resolver");
var register = new T();
register.RegisterEventHandlers(CqrsConfigurationResolver.Config);
return resolver;
} public static CqrsConfigurationResolver UseQueryEntryRegister<T>(this CqrsConfigurationResolver resolver)
where T : IQueryEntryRegister, new()
{
if (resolver == null)
throw new ArgumentNullException("resolver");
var register = new T();
register.RegisterQueryEntries(CqrsConfigurationResolver.Config);
return resolver;
} public static CqrsConfigurationResolver UseAuditingStore<T>(this CqrsConfigurationResolver resolver)
where T : IAuditingStore, new()
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<IAuditingStore,T>();
return resolver;
} public static CqrsConfigurationResolver UseAuditingConfiguration<T>(this CqrsConfigurationResolver resolver)
where T : IAuditingConfiguration, new()
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<IAuditingConfiguration, T>();
return resolver;
} public static CqrsConfigurationResolver UseUnitOfWork<T>(this CqrsConfigurationResolver resolver)
where T : IUnitOfWork
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<IUnitOfWork, T>(new PerThreadLifetimeManager());
return resolver;
} public static CqrsConfigurationResolver UseSession<T>(this CqrsConfigurationResolver resolver, LifetimeManager manager)
where T : IDpfbSession
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<IDpfbSession, T>(manager);
return resolver;
} public static CqrsConfigurationResolver UseAuditInfoProvider<T>(this CqrsConfigurationResolver resolver)
where T : IAuditInfoProvider
{
if (resolver == null)
throw new ArgumentNullException("resolver");
resolver.Use<IAuditInfoProvider, T>();
return resolver;
}
}

这里是一个调用的例子:

public static class ConfigurationInitializer
{
public static void Initial()
{
CqrsConfigurationResolver.Config
.UseCommandBus<DpfbCommandBus>()
.UseEventBus<DpfbEventBus>()
.UseCommandHandlerProvider<InterfaceBasedCommandHandlerProvider>()
.UseEventHandlerProvider<InterfaceBasedEventHandlerProvider>()
//.UseStorageRegister<FakeStorageRegister>()
.UseStorageRegister<EntityFrameworkStorageRegister>()
.UseQueryEntryRegister<QueryEntryRegister>()
.UseCommandHandlerRegister<DefaultCommandHandlerRegister>()
.UseEventHandlerRegister<DefaultEventHandlerRegister>()
.UseAuditingStore<MemoryAuditingStore>()
.UseAuditInfoProvider<NullAuditInfoProvider>()
.UseSession<HttpDpfbSession>(new PerHttpRequestOrThreadLifetimeManager())
.UseAuditingConfiguration<EnabledAuditingConfiguration>();
}
}

...

【想到什么再补充】

CQRS学习——IOC,配置,仓储隔离以及QueryEntry[其三]的更多相关文章

  1. CQRS学习——Dpfb以及其他[引]

    [Dpfb的起名源自:Ddd Project For Beginer,这个Beginer自然就是博主我自己了.请大家在知晓这是一个入门项目的事实上,怀着对入门者表示理解的心情阅读本系列.不胜感激.] ...

  2. 【转】Spring学习---Bean配置的三种方式(XML、注解、Java类)介绍与对比

    [原文]https://www.toutiao.com/i6594205115605844493/ Spring学习Bean配置的三种方式(XML.注解.Java类)介绍与对比 本文将详细介绍Spri ...

  3. spring基础:什么是框架,框架优势,spring优势,耦合内聚,什么是Ioc,IOC配置,set注入,第三方资源配置,综合案例spring整合mybatis实现

    知识点梳理 课堂讲义 1)Spring简介 1.1)什么是框架 源自于建筑学,隶属土木工程,后发展到软件工程领域 软件工程中框架的特点: 经过验证 具有一定功能 半成品 1.2)框架的优势 提高开发效 ...

  4. Docker学习笔记 — 配置国内免费registry mirror

    Docker学习笔记 — 配置国内免费registry mirror Docker学习笔记 — 配置国内免费registry mirror

  5. JMeter学习-010-JMeter 配置元件实例之 - CSV Data Set Config 参数化配置

    众所周知,在进行接口测试的过程中,需要创建不同的场景(不同条件的输入,来验证不同的入参的返回结果).因而,在日常的自动化接口监控或商品监控等线上监控过程中,需要配置大量的入参来监控接口的返回是否正确. ...

  6. JMeter学习-018-JMeter 配置元件之-HTTP信息头管理器-实现 Cookie 登录

    之前写过一篇通过[HTTP Cookie管理器]实现登录态操作的文章,使用时需要配置每个键值对(如下图所示),相对来讲配置比较繁琐.其实,我们也可通过在[HTTP信息头管理器]添加 Cookie 信息 ...

  7. JMeter学习-014-JMeter 配置元件实例之 - 用户定义的变量 参数化配置

    前文讲述了通过 CSV Data Set Config 实现参数化配置(详情敬请参阅:JMeter学习-010-JMeter 配置元件实例之 - CSV Data Set Config 参数化配置), ...

  8. JMeter学习-012-JMeter 配置元件之-HTTP Cookie管理器-实现 Cookie 登录

    前文我们讲过了若何获取登录后的 Cookie 信息,不知如何获取登录 Cookie 的朋友,敬请参阅我之前写的博文:Fiddler-005-获取 Cookie 信息.参阅上篇文章,获取到 Cookie ...

  9. oracle学习笔记——配置环境

    题记:最近再学oracle,于是按照这本经典的书<Oracle Database 9i/10g/11g编程艺术>来学习. 配置环境 如何正确建立SCOTT/TIGER演示模式 需要建立和运 ...

随机推荐

  1. C语言---翻译过程

    c的实现中包括两种环境: 1.翻译环境(translation environment):源程序---->机器指令 2.执行环境(execution environment):执行机器指令 这两 ...

  2. 关于git的打patch的功能

    UNIX世界的软件开发大多都是协作式的,因此,Patch(补丁)是一个相当重要的东西,因为几乎所有的大型UNIX项目的普通贡献者,都是通过 Patch来提交代码的.作为最重要的开源项目之一,Linux ...

  3. android之APP+JNI+Drv框架

    以LED为例 APP: JNI之java JNI之c DRV 项目组成:1.应用部分 1.1 APK(android工程) 1.1.1 java(功能) 1.1.2 xml(界面) 1.1.3 JNI ...

  4. socket编程发送GET请求

    可以根据几根url地址,分析出主机,地址,协议等,然后用封装成的类拼接成GET请求信息,用fsockopen连接主机,进行读取操作,获取响应信息,打印 <?php //http连接接口 inte ...

  5. Java的内存泄漏_与C/C++对比(转载总结)

    原文网址:http://developer.51cto.com/art/201111/302465.htm Java内存泄露的理解与解决(1)   一般来说内存泄漏有两种情况.一种情况如在C/C++ ...

  6. Hudson的安装配置

    Hudson的安装配置   目录 一.正文... 2 1.安装配置jdk. 2 2.安装配置tomcat7. 2 3.安装Hudson. 2 4.启动tomcat. 2 5.初识Hudson. 3 6 ...

  7. 第一篇、C_高精度加法

    简介: C语言中,整型占4字节,现在要计算两个100(假设)位以内的数想加,如果只是用整型去存储,明显就会越界.那么,我们有什么好的方法去完成这一操作呢? 1.用数组实现 数组中可以可以存储一定长度的 ...

  8. UITabBar - 深度解剖

    for (UIView *tabbarbutton in self.subviews) { //        NSLog(@"%@",tabbarbutton);         ...

  9. [译]Autoprefixer:用最可行的方式处理浏览器前缀的CSS后处理器

    Autoprefixer,通过Can I Use数据库来确定哪些浏览器前缀是需要的,然后解析CSS文件,将前缀添加到CSS规则里. 你所要做的就是添加你的资源构建工具(比如:Grunt),然后你就可以 ...

  10. 二叉搜索的各种bugs——重复递增序列

    int binary_search(int* A, int value, int p, int r); int main(int argc, char *argv[]){ , , , , , , , ...