用领域事件模拟AOP注入

12-04-10 gameboyLV
欢迎围观KylinORM系列文章:

第一篇:使用Tag网络维护实体关系

第二篇:基于业务驱动的领域服务

第三篇:使用领域事件模拟AOP注入

使用AOP织入领域对象可以方便地实现级联加载、数据校验、缓存、日志等功能,而不必将代码放在领域对象的基类或仓储对象的基类中。


使用AOP动态创建领域对象的Proxy实例,并按需要实现指定的接口。


可惜AOP(.NET)必须在运行时使用IL字节码动态创建类,或者让目标对象继承ContextBoundObject。有没有更简便的方法呢?看这段代码:

public class OrderInfo
{
    public IAspectMapper<OrderInfo> Mapper; //注册实体映射器
    public OrderInfo()
    {
        this.Mapper = AspectMapper.Inject(this, "OrderID") //注入实体并拦截领域事件
            .Before(MapperEvent.EntityCreate, Validator.Validate) //在实体创建之前调用权限控制模块
            .AfterReturning(MapperEvent.EntityCreate, Logger.Log); //在实体创建之后调用系统日志模块
    }
}
<p>

OrderInfo是一个普通的实体(POCO),在实体中声明一个映射器用于管理OrderInfo和其他实体的关联。然后使用Before拦截器拦截EntityCreate事件,使用AfterReturning拦截器拦截EntityCreate事件。

当对实体执行创建、更新、删除等操作时,数据层会首先检查实体映射器上注册的拦截器,调用相关的响应方法,根据方法的返回值再决定是否要执行真正的操作。


事件的响应Logger.Log可以指定任意数量的重载,事件源应根据实体和操作信息自动匹配最合适的方法。

public class Logger
{
    public static void Log(OrderInfo sender, AfterReturningEventArgs e)
    {
        //e.EventType 需要响应的实体操作
        if (e.EventType == MapperEvent.EntityCreate)
            Debug.WriteLine(string.Format("订单 {0} 已创建", sender.OrderNo));
    }
    public static void Log(object sender, AfterReturningEventArgs e)
    {
        Debug.WriteLine("测试");
    }
}
<p>

数据映射器可以代理任意对象的任意操作,只需要将操作TargetClass.DO更改为AspjectManager.Invoke(TargetClass.DO)即可。在Invoke之前AspjectManager会检查TargetClass.Mapper上注册的拦截器。

虽然需要在POCO对象中注册一个小小的属性,但是这点代价和动态类型、继承基类比起来就微不足道了。

相关示例和文档请参见 http://www.kylinorm.org/

[该贴被gameboyLV于2012-04-10 23:19修改过]

                   

12
gameboyLV
2012-04-10 23:21
似乎一张帖子只能发3张图


banq
2012-04-11 15:53
非常不错,和JdonFramework区别在于,JF响应是基于内存中领域对象,而你的框架是基于持久层的实体。

各有优缺点,KylinORM框架非常类似开源内存数据库Java-Chronicle:

http://www.jdon.com/jivejdon/thread/43888

都是在持久层这里做文章,所不同的是KylinORM是框架,可以搭配很多数据库,而Java-Chronicle是一个最终技术产品。

都属于不同的细分市场。

gameboyLV
2012-04-12 07:52
感谢banq老师,每次回复都能给我带来灵感。

可能是对我领域模型的理解不够深入,在我想象中领域模型应该是纯业务的,和持久层没有任何关系。领域模型获取和更新数据都应该直接操作缓存层,缓存层就类似一个面向对象的数据库。

当缓存层接到查询请求时会直接从memory cache中返回数据,接到写入或更新请求时会直接将请求写入一个队列,然后根据需要批量将队列提交到持久层。

而创建kylinorm这个试验品的目的就是为了将领域模型中的持久化操作完全分离,领域通过消息机制和object pool打交道。object pool的管理者就是kylin orm,而存放object的地方是一个运行在IIS上的超轻量级数据库,比如SQL CE 4.0。

orm定期将pool中的数据同步到数据库服务器。这样就走上了一条与贫血模型 完全相反的道路,业务层只负责封装对外的API和调度业务,领域层只负责实现业务逻辑、发送事件到缓存层,缓存层负责管理查询和写入操作。(是缓存所有的数据库操作,不是简单的缓存数据)

[该贴被gameboyLV于2012-04-12 07:52修改过]

banq
2012-04-12 08:23
2012-04-12 07:52 "@gameboyLV"的内容
领域层只负责实现业务逻辑、发送事件到缓存层,缓存层负责管理查询和写入操作 ...

明白了,相当于Jdon框架 + Java-Chronicle。Jdon框架没有捆绑持久层方式,而你的框架采取事件驱动顺便解决了持久层,方便用户直接使用。

但是有一个问题也在困扰我,你可能发现我一直在鼓吹传统事务锁的消亡,比如数据库锁或JTA等锁,这些都是性能杀手,虽然Scala提出内存事务机制一说,但是我比它更激进,我倡导弱一致性:弱一致性在现实世界中到处存在

那么对于你的整合了持久层的框架来说,你可能需要解决缓存层领域模型更新和持久层数据更新的事务一致性问题了,就如同国外另外一个CQRS框架Axon一样,也花大力气提供事务机制。

猜你喜欢
2Go 1 2 下一页