首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

《The Definitive Guide to Grails》 学习札记八 (对应第11章)

2012-12-23 
《The Definitive Guide to Grails》 学习笔记八 (对应第11章)1. Service层:在企业应用中,应该提供一个抽象

《The Definitive Guide to Grails》 学习笔记八 (对应第11章)

1. Service层:在企业应用中,应该提供一个抽象层,封装业务逻辑,降低MVC各层之间的耦合度。Service层就提供了一种把应用逻辑集中化到一套 API供controller和其它service使用的机制。封装业务逻辑到Service层的主要需求是:* 集中化业务逻辑到一套Service API;* 应用在多个Domain类上运行,复杂的业务模型难以在controller的逻辑中实现;* 用户案例和业务流程更适合封装在Domain对象之外的API里。当然,Service会有很多的dependencies,例如持久层数据源(JDBC,ORM),Session Factory,或其他的Service等,以松耦合的方式配置这些dependencies曾经是很困难的,但是如今有了反转控制(IoC,或者依赖注入--dependency injection)设计模式,Spring已经实现了这个模式,提供了IoC容器,Grails也是使用Spring来配置,因此Service的实现可以非常简单。2. Service和依赖注入:值得注意的是,Service缺省是singleton(单例),也就是说应用里只有一个Service实例。那如何才能在 Controller里得到service的引用呢?这就是Spring的依赖注入的好处所在,只需在controller里定义一个同名(首字母小写)的属性,service就能被注入到其中了。例如:class StoreController {? ? def storeService //注入Service,并且是动态的type,有利于测试controller时注入模拟的service? ? .... //可以直接调用Service中的方法}让grails管理service实例的注入,而不要自己初始化一个实例,特别是在事务处理中,自动注入的实例可以提供很多便利。3. Service的使用:使用Service的主要目的是保持Controller的紧凑和简洁,不在Controller中处理复杂的业务逻辑。例如:class StoreControler {? ? def storeService? ? def buyFlow = {? ? ? ? ........? ? ? ? flow.payment = storeService.purchaseAlbums(user, flow.creditCard, flow.albumPayments)? ? ? ? ........? ? }}4. 事务处理:Service经常涉及到多个Domain类的数据处理,因此需要确保事务的完整性,需要通过事务处理(transaction,all- or-nothing策略)的ACID原则实现,ACID是以下几个概念的简称:Atomicity:一个事务中的所有任务要么全部完成,要么一个都不成功;Consistency:任何对数据的操作之前和之后,数据库的状态都是一致的;Isolation:事务处理孤立于其他操作之外,在事务处理完成之前,不能插入其他查询或操作;Durability:事务处理完成后就不能被取消。Service中有一个属性叫transactional,如果被设为true,则Spring就产生一个Spring proxy,对每个service方法进行事务管理。如果需要自己管理事务,也可以把transactional设为false,然后通过 withTransaction方法的闭包来进行自己定制的事务管理,这时,如果在withTransaction方法内部发生了异常,则withTransaction中的所有事务就会发生回滚。假如对于回滚的部分也需要自己控制,可以给withTransaction的闭包传递一个org.springframework.transaction.TransactionStatus接口的实例作为参数,通过这个实例的 setRollbackOnly()方法进行回滚,如上一章所介绍的那样。5. Service的Scope:Service缺省是singleton,不允许多个request并发调用,也不是同步的,不能用于有状态的环境(如 flow)。但grails允许设定service的scope,包括:prototype:每次注入新的class都产生一个新的servicerequest:对每个request产生一个新的serviceflash:对当前和下一个request产生一个新的serviceflow:对整个flow保持同一个serviceconversation:对整个flow及其subflow保持同一个servicesession:对每个user session产生一个新的servicesingleton:缺省的,每个service在整个系统中只有一个实例如果使用flash,conversation或flow scope,service类必须实现java.io.Serializable接口。如果不是使用缺省的singleton,必须在service类里声明一个静态属性scope,并赋予其相应的值,例如:class LoanCalculationService {? ? boolean transactional = true? ? static scope = "request"? ? ......}singleton是最优选择,如果一定要选择有状态的scope,需要慎重考虑,尽量符合应用的特点。6. 向外部应用提供service:有一些grails插件支持对各种外部系统暴露service,例如JMX(Java Management Extensions)或XFire。在service类中定义expose属性,例如:package com.g2one.gunesclass GtunesService {? ? static transactional = true? ? static expose = ['jmx', 'xfire']? ? int getNumberOfAlbums() {? ? ? ? Album.count()? ? }? ? ...}还有一种方式是在grails应用启动之前,设置JAVA_OPTS的环境变量com.sun.management.jmxremote,如:set JAVA_OPTS = -Dcom.sun.management.jmxremote7. 查看Service的情况:可以利用JConsole(一个GUI图形界面的工具)来查看service及其执行的情况。

热点排行