【SQL开源代码栏目提醒】:网学会员为广大网友收集整理了,Domain-Driven Design(DDD)开源框架 - 讲义教程,希望对大家有所帮助!
JdonFrameworkDomain-Driven DesignDDD
开源框架banq jdon.comSimplify the BestJdonFramework Domain Model In-memory Events.能够在一两个小时内快速开发简单应用系统。
能够在此架构基础上无缝平滑发展成为一个可方便维护、可灵活拓展、可伸缩的中大型系统。
JdonFramework以下简称JF就是这样一个简单易用设计理念一直国际领先的轻量Java框架。
JavaEE多层架构MVC表现层struts1.xStruts2JSFTapestryWicket持久层HibernateSQLIBatisNoSQL服务业务层JdonFramework领域模型JdonFramework特点DDD 领域驱动设计通过突出领域模型作为整个系统的中心作用以领域模型的设计驱动表现层和数据库的开发设计。
IOC或DI完全自动识别的依赖注射模式可以完全摆脱类与类之间的依赖关系大大提高开发效率和重构速度。
In-memory Cache内置缓存自动支持借助Terracotta能够无缝将应用程序拓展到云计算架构。
Evans DDDDDD特点统一语言一个无处不在ubiquitous 的语言项目中所有人统一交流的语言。
减少沟通疑惑减少传达走样。
使得软件更加适合需求。
统一领域模型领域专家和程序员统一使用一种模型没有数据库数据表等专业软件技术干扰。
专门的业务领域层领域层除了业务没有其他没有软件架构框架等等底层技术。
DDD优点坏设计失血贫血模型将业务逻辑写在Servlet 、Jsp、MVC的Controller、SOA的服务中技术架构驱动数据模型数据模型只是一个数据的集合。
模型对象中只有setter/getter方法无其它业务方法称为失血或贫血模型。
失血模型导致软件复杂时可扩展性和性能大幅度降低难于提升。
随着时间推移开发效率降低。
JF架构特点领域模型驱动技术架构领域模型是富充血模型类似人类的DNA是各种重要事件导向的开关。
用户触发事件事件直接激活领域模型的方法函数再通过异步事件驱动技术活动如存储数据库或校验信用卡有效性等。
2009年推出Domain Model In-memory Events.2001年Martin fowler的LMAX架构推荐In-memory Event Sourcing架构。
JF的五种模型组件一. 实体聚合根对象元注释Model二. 服务Service 元注释Service三. 普通类组件构件Component四. 生产者Prodcuer-消费者模型send Consumer五. 拦截器 Interceptor 首先需要导入点IntroduceAll in com.jdon.annotation.领域模型和技术组件Model 领域模型包括实体模型值对象和领域服务与技术架构无关。
相当于鱼生存空间是缓冲器中Service/Component 技术组件架构用以支撑领域模型在计算机系统运行的支撑环境相当于鱼生活的水。
空间在Context container例如ServletContext中。
两者以Domain Events模式交互:异步命令。
Domain Events在Evans DDD实现过程中经常会碰到实体和服务Service以及Repository交互过程这个交互过程的实现是一个难点也是容易造成失血贫血模型的主要途径。
Domain Events提出解决方案JF提供的异步观察者模式为Domain Event实现提供更优雅的解决方案。
详细文章见http://www.jdon.com/jivejdon/thread/37289技术听命于领域模型调遣一个领域模型不但包含需要被持久化的业务数据同时还有业务操作并且有自己的继承体系。
Martin Fowler简称MF认为具备这些才可称为是一个领域模型。
很多人对MF这段理解以为使用Hibernate等ORM框架就可以JdonFramework不认为这样因为当使用这些ORM框架时还需要在模型之外实现操作xxx.savemodelJdon框架提供了Domain Events就可以在模型内部调用Hiberbate的xxx.savemodelDoamin Model Domain Events Hibernate才是真正实现MF的这段领域模型定义。
Domain Events图符合CQRS命令查询分离User interfaceServiceDomainEvent/Message BUSInfrastructureQuery/ReportingCommandsCommandsEvents领域事件起点内存中实体模型使用DDD从需求中获得实体模型后使用JF的Model加以标识。
每个实体模型必须有一个唯一标识如User对象必须有一个userId。
该实体模型必须以Model注解。
以Model标注的对象实例将存在缓存中常驻内存In-memory。
Modelpublic class MyModel private String userIdprivate String name....使用Annotation激活In-memory从数据库读取模型数据转换成模型对象时DDD称为Repository仓储在这个类上必须加入Introduce“modelCache” Around。
这一步确保领域对象每次加载在内存都是唯一的In-memory。
这对于后面使用domain events是必须关键重要步骤Source: com.jdon.sample.test.domain.onecase.repository.RepositoryImp Domain Model EventDomain Model ModelOther ComponentsComponetLoggingConsumerGUIMVCClientPersistenceConsumerasyncMessageasyncMessageasyncMessageComponent architectureDomain Events两种实现异步模式 生产者-消费者模式。
主题topic和Queue队列两种。
领域模型是生产者消费者有两种1.Consumer可以实现1:N多个内部机制使用号称最快的并发框架Disruptor实现。
适合轻量小任务原子性无状态。
2.Componet直接使用普通组件类作为消费者使用jdk future机制只能1:1适合大而繁重的任务有状态单例。
Domain Events 工作原理Domain Model ModelConsumerConsumerComponentDisruptor或Java concurrent FutureDomain MessagePool.run使用Java concurrent的‘Future’ API相关更详细原理见“使用future实现内置异步API” Domain Events: 实现第一步1 . 使用Model 和Introduce“message”标注实体类2 . 使用Send“mytopic” 标注该实体中的发送方法Source :com.jdon.sample.test.domain.onecase.DomainEventDomain Events: 第一步Introduce“message”“message” 表示引入JF配置aspect.xml中消息拦截器om.jdon.domain.message.MessageInterceptor通过该配置让该模型类成为消息生产者或发送者。
Send“mytopic”: “mytopic”是消息topic名称可自己取但是和消费者的标注Consumer“mytopic”是一致的表示生产者将消息发往这个topic中在send标注的方法中你还需要将你要传送给消息消费者使用的数据打包进入DomainMessag对象该方法的返回类型必须是DomainMessag.Domain Events: 第二步1 标注消费者Consumermytopic2. 消费者类必须实现接口com.jdon.domain.message.DomainEventHandlerSource:com.jdon.sample.test.domain.onecase.MyDomainEventHandler消费者注意项如果有多个消费者订阅了同一个主题Topic那么这些消费者之间的运行顺序是按照他们的类名字母先后的。
如AEventHandler先于BEventHandler先于CEvent…等。
消费者的主要内容写在onEvent中可通过event.getDomainMessage获得生产者你要传递的数据。
客户端调用
代码JdonFramework客户端可以是在Web的Servlet或Jsp中调用也可以在Application调用如下ContainerSetupScript css new ContainerSetupScriptcss.preparecom.jdon.jdonframework.xml daAppUtil appUtill new AppUtilcom.jdon.jdonframework.xmlIServiceSample serviceSample IServiceSample appUtil.getServiceserviceSampleString res String serviceSample.eventPointEntryhelloAssert.assertEqualsres eventMessagehello源码见:com.jdon.SampleAppTest事件Topic主题好处原子性Martin fowler :LMAX Architecture中认为可替代传统数据库事务或会话事务。
可将原来一整块事务切分成多个单个事务处理器消费者比如保存到数据库和lucene文件如果捆绑在一个事务由于文件保存很慢导致数据库保存拖延可切分成两个事件消费者异步实现。
见jivejdon的Repository中的SaveMessage.java。
另外一种Queue实现Sendtopic Componenttopic消费者直接是Componenttopic 标注的类必须实现接口com.jdon.domain.message.MessageListenerJF 6.3之前缺省的Domain Events实现。
使用JDK的future实现。
保留在新版本中。
Domain Events领域事件技术特点并发策略异步消息懒惰加载 使用java 并行模型Domain Events 类似Actor Model消息是异步非堵塞发送和接受属于“fire-and-forget”。
Disprutor的LMAX团队测试Actor模型是有瓶颈的所以他们采取Disruptor.DCI Architecture在具体运行场景时通过将业务逻辑方法注射到Model标注的领域模型对象中领域事件的更多优点松耦合业务逻辑能够与技术架构解耦将”做什么”和”怎么做”分离EDA架构Event-driven Architecture异步事件驱动模式异步懒惰加载Asynchronous Lazy-load类似函数式语言的懒功能只有使用时才真正执行。
真正可伸缩性通过与JMS结合可以在多核或多个服务器之间弹性扩展。
事件应用异步懒加载即用即取数据随时运算。
函数功能只有在它的返回结果需要时才真正执行计算类似erlang Scala等函数式语言。
再也Hibernate LazyInitializationExceptions错误烦恼没有Session持续打开Session打开就是数据库连接一直打开耗费资源性能杀手不需要Open Session in View 反模式不再需要使用SSH或S2SH组合中在web.xml配置Spring的OSIV过滤器这时耗费资源和危险的特别是嵌套错误抛出时。
可以在MessageListener处集成入JMSJMS是可伸缩性并带有分布式事务方案可以保证持久化等事务精确完成。
事件应用模型的异步 懒加载假设computeCount是一个非常耗CPU的任务使用并发策略可以消除这种延迟。
publicintgetMessageCountDomainEvents domainEvents ifmessageCount -1 ifmessageCountAsyncResult null messageCountAsyncResult domainEvents.computeCountaccount.getUserIdLong elsemessageCount Integer messageCountAsyncResult.getEventResultreturnmessageCount 事件应用异步调用第一次调用getMessageCount方法激活耗时的domainEvents.computeCount. 方法这次调用中我们可以不需要范围结果。
第二次再次调用getMessageCount将得到前面耗时的计算结果我们可以通过AJAX实现二次调用。
Download Sample Source集成JMSComponent“JMSListener ”public class JMSListener implements MessageListenerpublic void actionDomainMessage message Connection connection connectionFactory.createConnectionSession session connection.createSessionfalseSession.AUTO_ACKNOWLEDGEMessageProducer producer session.createProducerdestinationTextMessage message session.createTextMessagemessage.getSourceproducer.sendmessage可伸缩架构变迁之路基本逻辑约束一致性方法DDD充血领域模型薄Service薄Action分布式可伸缩方向等等使使用DDD后的架构传统老架构JF分布式架构Domain ModelJMSPersistenceSend EmailOther ServicesMessageDomain ModelMessageDistributed CacheDistributed Cache基于领域模型的分布式架构领域模型 分布式缓存 存储 JMS异步领域模型带着逻辑和数据被分布式缓存如Ehcache Terracotta分布到多台机器中运行。
领域模型通过JMS驱动技术架构实现功能。
JMS 集群无单点分布式事务架构业务数据装在领域模型中关系数据库只是用来做存储NoSQLNot Only
SQL领域模型数据和数据库数据不高度一致低延迟。
JdonFramework特点DDD 领域驱动设计通过突出领域模型作为整个系统的中心作用以领域模型的设计驱动表现层和数据库的开发设计。
IOC或DI完全自动识别的依赖注射模式可以完全摆脱类与类之间的依赖关系大大提高开发效率和重构速度。
Cache内置缓存自动支持借助Terracotta能够无缝将应用程序拓展到云计算架构。
Ioc/AOP轻量容器依赖或或者控制关系的反转注射Ioc模式通过配置/微容器解决POJO调用关系。
高度灵活和松耦合实现对象的可更换。
面向方面编程AOP提供在不改变原来架构基础上动态增加/更换一些普遍功能。
Out-of-the boxJF注射和拦截架构Model模型中可以通过字段的Inject将其他类注射进入包括Component类。
被注射的类如果有Introduce将再次引入拦截器。
Component技术架构中组件可以通过构造器直接注射进入其他Component组件被注射的类如果有Introduce将再次引入拦截器。
灵活的注入和拦截依赖注入Dependency InjectionDI or IOC Service or Component 能够进行彼此注入通过其类构造器不支持setter方法注入.Service or Component也能被注入到Model 领域模型中或者使用domain events.面向方面编程Aspect-oriented programmingAOP使用Introduce: Service or Component 能够将彼此引入作为拦截器. Model 能引入任何POJO 或Component作为它的拦截器Model内部机制Clientxx.getA“a”AModelInterceptor for Awith Introduce B that needimplements interfaceand has IntroduceInject proxy of BInterceptor for Bwith IntroduceCache containerCInject proxy of cComponentIn Context Containerinterceptor模型内注射Component内部机制Clientxx.getA“a”A ServiceInterceptor poincutserviceB that needimplements interfaceComponentInject proxy of BInterceptor for Bwith IntroduceContext container ServletContext如何调用一个有依赖的服务AOP Introduce使用方法Introduce名称 为当前类引入拦截器可以用在Model或Component中名称是拦截器的Component名称. 例如Introducec ---Component“c”在当前类具体方法上使用Before After和Around三种拦截器激活的方式。
注意使用Around对拦截器有特定写法要求其他无。
Introduce 引入拦截器被Introduce 引入的拦截器ComponentcpublicclassC //被拦截器的Input参数将注射到inVal中publicObject testOneObject inVal …. //testOne 方法return 结果将被注射到被拦截器的return中//被拦截器的方法myMethod2返回值将被引入此方法的inValepublicObject testWoObject inVal ……Introduce的Around如果某个类似于Introduce的Around那么对被引入的拦截器有特殊要求写法Interceptor“aroundAdvice”//1. 需要表明自己是InteceptorpublicclassAroundAdvice implementsMethodInterceptor //2.需要实现org.aopalliance.intercept.MethodInterceptor接口//3.完成接口的Invoke方法publicObject invokeMethodInvocation invocation throwsThrowableObject o invocation.proceed//在此方法前后写包围around
代码。
JF拦截器第二种写法//1. 指定被拦截的类是Component“a”和Component“c”Interceptorname myInterceptor pointcut acpublic class MyInterceptor implements MethodInterceptor //2.需要实现org.aopalliance.intercept.MethodInterceptor接口//3.完成接口的Invoke方法public Object invokeMethodInvocation methodInvocation throws java.lang.Throwable …被拦截器的类没有特别规定写法只要标注Component“a”就可以至于拦截a的什么方法在拦截器invoke中实现。
该方式将拦截定义在拦截器这里和Introduce定义正好相反。
自动注射的两个优势完全可定制面向对象编程之父Grady Booch 说对象最伟大之处在于其可被替代The great thing about objects is they can be replaced而JF伟大之处是帮助你替代这些对象甚至包括JF本身。
无需对象创建颠覆对象使用之前必须创建的基本定律正象无需关心对象销毁一样您可以无需关心对象创建。
上一篇:
十大免费开源网店系统PK
下一篇:
青青子衿,悠悠我心