锁定老帖子 主题:我是如何写Service的
该帖已经被评为新手帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-03-03
最后修改:2010-03-05
马上要告别研发了,所以写一些自己积累的经验,用来纪念4年的似水流年,本篇为第一张,用来介绍自己是如何写Service的,当然我总结的不一定合理,大家一起讨论下。
笔者认为,Service及服务层,服务可以分为功能服务和业务服务,功能服务不易改变,业务服务易改变。所以功能服务添加得多,修改的少,那么我们可以考虑不使用接口。而业务服务,修改和更新都很频繁,所以应该提取接口,用不同的实现来屏蔽业务逻辑。
1:使用断言控制输入。 使用断言来判断有效的输入,这样能够避免异常的扩散,迅速定位错误和减少BUG出现的几率。 如: import org.springframework.util.Assert; private boolean addAttachment(Attachment att) { Assert.notNull(att, "att对象不能为空"); } 要学会灵活运用断言,不仅仅是用来断言来判断方法的输入参数是否正确,还可以判断业务逻辑,每次方法调用的输入输出,至于何时使用需要自己根据方法自我判断。
2:只抛出RumtimeException 作为service层,自己不清楚调用方到底是谁,也不知道调用方如何使用自己的接口,那么自己写出的接口最好是抛出RumtimeException,这样调用方能够处理这个异常或者觉得处理这个异常有必要的话,就进行处理。如果使用Exception就得强制那些处理不了的调用方继续向外抛出。抛出RumtimeException的时候需要在注释里申明我抛出了该异常。 throw new RuntimeException("工作流初始化失败!");
3:在Service层做事务处理 大家都知道Service层一般是用来组合DAO,所以经常出现需要事务处理的地方,笔者建议尽量在service层做事务处理。 因为一般业务逻辑都屏蔽在service层。笔者习惯使用Spring的手动事务。 new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() { protected void doInTransactionWithoutResult(TransactionStatus status) { //调用DAO按照ID删除部门 } });
4:Service接口的异常处理 对于程序异常,service能够处理的自己处理(将异常封装成自己的异常,再向外抛出也算一种处理),不能处理的继续向外抛出。 对于业务异常,以前开发的时候都会向外抛出一个用户友好的运行时异常,这种异常信息是能够直接展现给用户的,如“您添加的用户名已经存在!”,但是现在考虑到国际化,所以觉得Service的接口应该抛出错误代码,定义一个友好错误代码运行时异常,在程序出现条件错误的时候抛出错误代码。错误代码可以定义一个枚举类来实现。 /** * 错误代码定义 * * @author fangtengfei * @date 2010-3-3 */ public enum ErrorCode { /** * 用户不能重复 */ User_Not_Repeat, /** * 用户名太长 */ User_Name_Too_Long } 在Service里抛出:throw new FriendlyCodeRuntimeException(ErrorCode.User_Not_Repeat.toString());
5:必须记录日志 大家都知道,记录日志的目的,主要是当程序运行在不同的环境下,使用日志来监控程序的运行,有些异常可能会特定的环境发生,而这种环境不容易被重现,所以此时唯一能定位问题的途径就只有日志。 Service层会被各种调用方使用,特别是对外提供Service,环境更会前差万别,如何迅速并有效的定位错误变得尤其重要,所以必须记录有效的日志。 logger.error("更新文档出现出错", e);
6:写有效的注释 之所以说写有效的注释,是因为有时候,有些方法真的不需要写注释,如addUser,就不要在写注释“添加用户”这样的注释。关键是写有效的注释,注释的作用在于,调用方只看注释而不看代码就能知道如何使用接口,注释应该包括:输入参数的注释,输出参数的注释和异常的注释。特别是List<Map>,Sting[]这样的参数要严格说明,笔者认为Service作为一个核心层,注释必须非常详细。另外直观的方法名也能起到注释的作用。 /** * 批量添加文档的附件 * * @param att 附件对象,附件名长度为20,附件大小为10M * @throws FriendlyCodeRuntimeException */ private void addAttachment(Attachment... attachment)
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-03-03
看的lz对service层理解比较深刻学习了 就是太少了
|
|
返回顶楼 | |
发表时间:2010-03-03
最后修改:2010-03-03
主要是总结一些有价值的经验,写太多大家看得也烦 呵呵
|
|
返回顶楼 | |
发表时间:2010-03-03
最后修改:2010-03-03
用回调来管理事务....
逻辑一多.... 几乎想死. |
|
返回顶楼 | |
发表时间:2010-03-03
抛出异常的爱 写道 用回调来管理事务....
逻辑一多.... 几乎想死. 呵呵 我有时候也遇到过这种问题,事务中包含的业务逻辑都会很多,而且参数都必须定义为final的,不知道您有什么好的解决办法? |
|
返回顶楼 | |
发表时间:2010-03-03
最后修改:2010-03-03
fantasy 写道 抛出异常的爱 写道 用回调来管理事务....
逻辑一多.... 几乎想死. 呵呵 我有时候也遇到过这种问题,事务中包含的业务逻辑都会很多,而且参数都必须定义为final的,不知道您有什么好的解决办法? 没好办法 以测试困难为由... 建议大家改用DAO来作了. 而且runtimeException容易忘记对业务错误进行处理..... 就是打有关业务的日志... |
|
返回顶楼 | |
发表时间:2010-03-03
抛出异常的爱 写道 fantasy 写道 抛出异常的爱 写道 用回调来管理事务....
逻辑一多.... 几乎想死. 呵呵 我有时候也遇到过这种问题,事务中包含的业务逻辑都会很多,而且参数都必须定义为final的,不知道您有什么好的解决办法? 没好办法 以测试困难为由... 建议大家改用DAO来作了. 而且runtimeException容易忘记对业务错误进行处理..... 就是打有关业务的日志... 在DAO里做,会不会出现事务嵌套?或者说有的方法无法做事务处理,我就出现过这种情况。 |
|
返回顶楼 | |
发表时间:2010-03-03
spring的自动代理事务不是很好嘛
|
|
返回顶楼 | |
发表时间:2010-03-03
赞同老抛的做法。
我的作法是统一叫Mgr,Dao叫BaseMgr,Service继承BaseMgr叫xxMgr |
|
返回顶楼 | |
发表时间:2010-03-03
按照系统的设计来说,事务控制放在业务层,当前Spring框架的事务在开发过程中,大部分人都是采用@Transactional注解或者是<tx:advice/>集合AOP的方式,能够提高开发效率。 LZ其实你应该总结出更多设计经验。 |
|
返回顶楼 | |