- 浏览: 160829 次
- 来自: ...
文章分类
- 全部博客 (151)
- Liferay.in.Action (3)
- 集群 (12)
- web (5)
- jna (2)
- 数据库 (7)
- Terracotta (11)
- xml (1)
- Hibernate (3)
- Jdbc (2)
- DDD (10)
- nosql (7)
- 云存储 (3)
- 云产品 (7)
- 云计算 (26)
- Hadoop (11)
- 虚拟化 (5)
- REST (3)
- 程序人生 (11)
- google (2)
- 安全应用 (5)
- LDAP (0)
- 安全技术 (5)
- android (4)
- 网络妙语 (1)
- HTML5 (1)
- 搜索引擎 (1)
- 架构设计 (5)
- redis (3)
- Cassandra (2)
最新评论
-
liwanfeng:
情况是这样的,你的文件我觉得还是比较小,我现在需要处理的XML ...
dom4j处理大文件
原文 http://www.jdon.com/jivejdon/thread/37712
Domain Events领域事件定义见这里Domain Events – 救世主
,领域事件可以实现领域业务模型与技术架构之间的松耦合,达到实现类似DCI架构
同样效果。
DCI是通过设定一个场景对象,让与这个场景有关的功能在场景中混合实现,注入参与者角色和参与模型;而领域事件则是通过松散的事件达到场景目标,不同场景对应不同领域事件。下面以JiveJdon
实例说明领域事件应用。
在JiveJdon
的Account中有一个计算该用户发帖总数字段messageCount,如下:
public
class
Account{
private
int
messageCount;
public
int
getMessageCount(){
return
messageCount;
}
}
这个messageCount是通过查询该用户所有发帖数查询出来的,也许你会问,为什么不将用户发帖总数设置为数据表一个字段,这样用户发帖时,更新这个字段,这样只要直接查询这个字段就可以得到messageCount?
没有设立专门持久字段的原因如下:
1. 从模型设计角度看:messageCount字段归属问题,messageCount其实是一个表示Account和Message两个实体的关系关联统计字段,但是这种关联关系不属于高聚合那种组合关系的关联,不是Account和Message的必备属性,根据DDD
的高聚合低关联原则,能不要的关联就不要,因此放在哪里都不合适。
2.从性能可伸缩性
角度看:如果我们将messageCount放在第三方专门关联表中,那么用户增加新帖子,除了对Message对应的表操作外,还需要对这个关联表操作,而且必须是事务
的,事务是反伸缩性
的,性能差,如果象messageCount各种统计字段很多,跨表事务
边界延长,这就造成整体性能下降。
3.当然,如果将messageCount硬是作为Account表字段,由于整个软件的业务操作都是Account操作的,是不是将其他业务统计如threadCount等等都放到Account表中呢?这会造成Account表变大,最终也会影响性能。
那么messageCount每次都通过查询Message对应表中用户所有发帖数获得,这也会导致性能差,表中数据越多,这种查询就越费CPU。
使用缓存
,因为Account作为模型被缓存
,那么其messageCount值将只有第一次创建Account执行查询,以后就通过缓存
中Account可直接获得。
所以,根据DDD
,在AccountRepository或AccountFactory实现数据表和实体Account的转换,Account中的值都是在这个类中通过查询数据表获得的。
当访问量增加时,这里又存在一个性能问题,虽然一个Account创建时,messageCount查询耗时可能觉察不出,但是如果是几十几百个Account第一次创建,总体性能损耗也是比较大的,鉴于我们对可伸缩性
无尽的追求,这里还是有提升余地。
从设计角度看,由于messageCount不是Account的必备字段,因此,不是每次创建Account时都要实现messageCount
的赋值,可采取即用即查方式。所以,我们需要下面设计思路:
public
class
Account{
private
int
messageCount = -1;
public
int
getMessageCount(){
if
(messageCount == -1)
//第一次使用时即时查询数据表
return
messageCount;
}
}
怎
么实现这个功能呢?使用Hibernate的懒加载?使用Lazy load需要激活Open Session In
View,否则如果Session关闭了,这时客户端需要访问messageCount,就会抛lazy
Exception错误,但是OSIV只能在一个请求响应范围打开,messageCount访问可能不是在这次请求中访问,有可能在后面请求或其他用户
请求访问,所以,这个懒加载必须是跨Session,是整个应用级别的.
实际上,只要Account保存在缓存
中,对象和它的字段能够跨整个应用级别,这时,只要在messageCount被访问即时查询数据表,就能实现我们目标,其实如此简单问题,因为考虑Hibernate等ORM框架特点反而变得复杂,这就是DDD
一直反对的技术框架应该为业务设计服务,而不能成为束缚和障碍,这也是一山不容二虎的一个原因。
这
带来一个问题,如何在让Account这个实体对象中直接查询数据库呢?是不是直接将AccountRepository或AccountDao注射到
Account这个实体呢?由于AccountDao等属于技术架构部分,和业务Account没有关系,只不过是支撑业务运行的环境,如果将这么多计算
机技术都注射到业务模型中,弄脏了业务模型,使得业务模型必须依赖特定的技术环境,这实际上就不是POJO了,POJO定义是不依赖任何技术框架或环境。
POJO是Martin Fowler提出的,为了找到解决方式,我们还是需要从他老人家方案中找到答案,模型事件以及Event模式也是他老人家肯定的,这里Account模型只需要向技术环境发出一个查询Event指令也许就可以。
那么,我们就引入一个Domain Events对象吧,以后所有与技术环境的指令交互都通过它来实现,具体实现中,由于异步
Message是目前我们已知架构中最松耦合的一种方案,所以,我们将异步
Message整合Domain Events实现,应该是目前我们知识水平能够想得到的最好方式之一,当然不排除以后有更好方式,目前Jdonframework
6.2已经整合了Domain Events + 异步
消息机制,我们就可以直接来使用。
这样,Account的messageCount即用即查就可以使用Domain Events + 异步
消息实现:
public
int
getMessageCount(){
if
(messageCount == -1) {
if
(messageCountAsyncResult == null
) {
//向技术环境发出查询获得messageCount值的命令,
//这个命令是在另外新线程实现,因此结果不一定立即返回
messageCountAsyncResult =
domainEvents.computeAccountMessageCount(account.getUserIdLong());
} else
{
//当客户端再次调用本方法时,可以获得查询结果,
//如果查询过程很慢,还是没有完成,会在这里堵塞等待,但概率很小
messageCount = (Integer) messageCountAsyncResult.getEventResult();
}
}
}
messageCount最后获得,需要通过两次调用getMessageCount方法,第一次是激活异步
查询,第二次是获得查询结果,在B/S架构中,一般第二次查询是由浏览器再次发出请求,这浏览器服务器一来一回的时间,异步查询一般基本都已经完成,这就是充分利用B/S架构的时间差,实现高效率的并行计算。
所以,并不是一味死用同步就能提高性能,可伸缩性
不一定是指单点高性能,而是指整个系统的高效率,利用系统之间传送时间差,实现并行计算也是一种架构思路。这种思考思路在实际生活中也经常会发生。
最
后,关于messageCount还有一些有趣结尾,如果浏览器不再发第二次请求,那么浏览器显示Account的messageCount就是-1,我
们可以做成不显示,也就看不到Account的发帖总数,如果你的业务可以容忍这个情况,比如目前这个论坛就可以容忍这种情况存在,Account的
messageCount第一次查询会看不到,以后每次查询就会出现,因为Account一直在缓存
内存中。
如果你的业务不能容忍,那么就在浏览器中使用AJAX再次发出对getMessageCount的二次查询,那么用户就会每次
都会看到用户的发帖总数,JiveJdon这个论坛的标签关注人数就是采取这个技术实现的。这样浏览器异步
和服务器端异步
完美结合在一起,整个系统向异步
高可伸缩性
迈进一大步。
更进一步,有了messageCount异步查询,如何更新呢?当用户发帖时,直接对内存缓存
中Account更新加一就可以,这样,模型操作和数据表操作在DDD
+ 异步
架构中完全分离了,数据表只起到存储作用(messageCount甚至没有专门的存储数据表字段),这和流行的NoSQL
架构是同一个思路。
由于针对messageCount有一些专门操作,我们就不能直接在Account中实现这些操作,可以使用一个专门值对象实现。如下:
public
class
AccountMessageVO {
private
int
messageCount = -1;
private
DomainMessage messageCountAsyncResult;
private
Account account;
public
AccountMessageVO(Account account) {
super
();
this
.account = account;
}
public
int
getMessageCount(DomainEvents domainEvents) {
if
(messageCount == -1) {
if
(messageCountAsyncResult == null
) {
messageCountAsyncResult = domainEvents.computeAccountMessageCount(account.getUserIdLong());
} else
{
messageCount = (Integer) messageCountAsyncResult.getEventResult();
}
}
return
messageCount;
}
public
void
update(int
count) {
if
(messageCount != -1) {
messageCount = messageCount + count;
}
}
}
注:以上功能已经在当前论坛实现。
相关文章:
Domain Events – 救世主
CAP原理和BASE思想
开源
Jdonframework
6.2全新发布
[该贴被admin于2009-11-22 08:11修改过]
[该贴被admin于2010-03-28 09:00修改过]
[该贴被admin于2010-03-28 09:01修改过]
[该贴被admin于2010-03-28 09:01修改过]
但是稍微有点不一样。
我在这介绍一下我这边本身设计。
DomainEvent
他只有 type:String,target:Object
两个属性
DomainEventListener
只是初步的设计了handle(de:DomainEvent):void
这样的方法
DomainContext
这个类把他看作是Observer就可以了。
是设计成了单例
在载入Account的时候,直接载入 messageCount的字段。用hibernate的foruma也可以。
之后如果这个对象存在于缓存 的话。
我是用了静态内部类来处理。
public class Account{
private int messageCount;
private AccountMessageCountListener amc = new AccountMessageCountListener ();
private static class AccountMessageCountListener implements DomainEventListener{
public AccountMessageCountListener (){
DomainContext.getInstance().addDomainEventLister(this);
}
public void handle(DomainEvent de){
if(de.getType().equals("Create_new_Message")){
Message msg = (Message) de.getTarget();
Account account = msg.getAccount();
account.messageCount = account.messageCount+1;
}
}
}
public int getMessageCount(){
return messageCount;
}
}
当然AccountMessageCountListener 这个类也可以做成单例
当然更新 messageCount的时候要锁住.在这边没加锁
当然在Service层(或者Manager层)save message (这里的save插入数据库成功)
成功之后要触发 Create_new_Message的DomainEvent事件
这样就直接更新了Account的MessageCount字段了。
你觉得呢
Bang
观察者模式有同步和异步 ,异步观察者模式就和消息生产和消费模式差不多了,Event-Listerner事件监听模式
在DDD 实践中,使用事件模式主要是为解决业务模型和技术架构耦合。
务器只有65535个端口,能够承载的连接可以计算一下能有多少。
其次、何时进行AJAX的更
再次,我不知道你的这个是否只能依赖于BS的结构
最后、如果异步 更新的消息队列出现了问题。
首先多谢你肯定这个idea, 你的疑问可能是大多数人的疑问:
这里的异步 是指一个分布式环境下异步 ,这样我们就能够将业务处理分到不同服务器执行,比如messagecount可以给另外一台服务器执行,那么客户端下次可能就到那台服务器获取结果,这个非常类似互联网网站设立专门的图形服务器一样,这里还有一个分布式job服务器架构
何时进行AJAX更新,这些都是由我们定义的,因为AJAX寄生在Jsp页面。
可以不依赖BS架构,多层架构C/S更容易实现。
消息队列可以采取JMS集群,没有单点风险。这样,整个分布式架构可以如下图:
发表评论
-
Domain Events异步应用-2
2010-11-03 22:43 992原文 http://www.jdon.com/jive ... -
Domain Events – 救世主
2010-11-03 22:34 972原文 http://www.jdon.com/jivejdon ... -
使用CQRS重新考虑架构
2010-11-03 22:25 1584原文 http://www.jdon.com/jivejdon ... -
DDD的革命: CQRS和Event Sourcing
2010-11-03 22:19 1318原文 http://www.jdon.com/jivejdon ... -
架构的演化和不断新兴的设计
2010-11-03 22:14 882原文 http://www.jdon.com/jivejdon ... -
浅谈领域驱动设计
2010-10-21 22:46 733原文 http://www.blogjava.ne ... -
对领域驱动设计的初步认识(三)
2010-10-21 21:52 1046原文 http://www.jdon.com/ji ... -
对领域驱动设计的初步认识(一)
2010-10-21 21:50 864原文 http://www.jdon.com/ji ... -
对领域驱动设计的初步认识(二)
2010-10-21 21:46 858原文 http://www.jdon.com/jivejdon ...
相关推荐
在C#中,我们通常使用实体(Entities)、值对象(Value Objects)、领域事件(Domain Events)、聚合根(Aggregate Roots)、工厂(Factories)和仓储(Repositories)等DDD模式。例如,"中介实体"可能是一个业务中...
4. **领域事件(Domain Events)**:当领域状态发生改变时,可以发布领域事件,用于通知其他服务或组件。在Node.js中,可以使用EventEmitter或第三方库如`@async/queue`来处理异步事件。 5. **领域服务(Domain ...
通常,领域模型包含了业务实体(Entities)、值对象(Value Objects)、聚合(Aggregates)、领域事件(Domain Events)、服务(Services)以及领域驱动设计(DDD)中的其他元素。 1. **业务实体(Entities)**:...
4. **领域事件(Domain Events)**:用于记录领域内的重要变化,可以异步处理,与其他系统或服务通信。 5. **领域服务(Domain Services)**:处理跨越多个聚合的业务逻辑,不包含在任何实体或值对象中。 接下来,...
Node.js Domain(域) 简化异步代码的异常处理,可以捕捉处理try catch无法捕捉的异常。 Domain 模块可分为隐式绑定和显式绑定: 隐式绑定: 把在domain上下文中定义的变量,自动绑定到domain对象 显式绑定: 把不是...
1. **领域**:业务领域的知识和规则,这是软件要解决的核心问题。 2. **实体**:具有唯一标识的业务对象,如用户、订单等。 3. **值对象**:关注于其属性而非身份的对象,如地址、金额等。 4. **聚合**:一组相关...
1. 定义数据模型。 2. 创建ALV控件。 3. 设置ALV属性。 4. 填充ALV数据。 5. 显示ALV。 - **1.2.2 显示ALV常用的两个FM** - `REUSE_ALV_GRID_DISPLAY`: 用于显示ALV网格。 - `REUSE_ALV_LIST_DISPLAY`: 用于...
AS3通过`flash.system.ApplicationDomain`和`flash.events.EventDispatcher`监听和发送消息,JavaScript通过`window.postMessage`方法接收和发送消息。 4. 常见问题与解决方案 - **安全性问题**:由于安全限制,...
事件在DDD中扮演着重要的角色,特别是领域事件(Domain Events),它们记录了领域模型中的重要业务变化。 **事件基础(EventBase)** "EventBase"可能是指在DDD中用于处理和存储事件的基础类或框架。这个基础类...
"Imagine.Mes.MesInspection.Domain"是领域层的实现,包含了业务实体(Entities)、值对象(Value Objects)、领域事件(Domain Events)和领域服务(Domain Services)。这个层专注于业务规则和业务逻辑,确保了...
3. **领域事件(Domain Events)**:当领域中的某个重要状态发生改变时,会触发领域事件。这些事件可以异步处理,以保持领域模型的简洁性。在.NET Core中,可以使用事件总线(Event Bus)来处理领域事件。 4. **...
Router1和Router2的E0端口均使用了C类地址192.1.0.0作为网络地址,Router1的E0的网络地址为192.1.0.128,掩码为255.255.255.192, Router2的E0的网络地址为192.1.0.64,掩码为255.255.255.192,这样就将一个C类网络地址...
6. ** Domain Events **:领域事件记录了业务流程中的重要事件,可以用来实现异步处理,解耦不同的系统组件。 7. ** Strategic Design **:包括子域识别、上下文映射等策略,帮助确定不同Bounded Context之间的关系...
4. 领域事件(Domain Events):DDD中,领域事件用于表示领域模型中发生的有意义的业务事件。它们在业务操作完成后发布,可以用来触发异步处理或与其他系统通信。 5. 仓储(Repository):仓库是领域模型与持久化...
7. **领域事件(Domain Events)** 领域事件是在业务操作完成后发布的,用来通知系统其他部分发生了什么。在ASP.NET MVC中,可以使用事件总线或者直接订阅/发布机制来处理领域事件,实现解耦和异步处理。 8. **上...
- **domain.create()、domain.run(fn)**: 创建和运行领域对象。 #### 九、事件处理 - **事件: 'exit'**: 进程退出时触发。 - **事件: 'uncaughtException'**: 未捕获异常时触发。 - **Signal Events**: 处理操作...
在Flex应用中,可以通过创建一个FileReference对象,然后监听其events来触发文件选择对话框。用户选择文件后,FileReference对象会包含所选文件的信息,如文件名、大小等。然后,我们可以调用FileReference的upload...
- **异步处理**:命令和事件可以通过消息队列异步处理,以提高系统响应速度和容错能力。 通过分析这个CQRS.Demo项目,我们可以学习如何在实际应用中有效地划分职责,理解CQRS如何提高系统的可读性、可维护性和可...
2. **领域模型**:是对业务领域的抽象表示,包含领域内的实体(Entities)、值对象(Value Objects)、聚合(Aggregates)、领域事件(Domain Events)等元素。领域模型反映了业务专家和开发人员对业务的理解。 3. ...