`
fantasy
  • 浏览: 517295 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

我是如何写Service的

    博客分类:
  • Java
阅读更多

马上要告别研发了,所以写一些自己积累的经验,用来纪念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)

 

 

 

 

分享到:
评论
32 楼 mikehuhu 2010-03-04  
看到lz暴露了名字?
31 楼 commx 2010-03-04  
感谢fantasy的总结,受益良多,对断言的理解一语中的
30 楼 zy2419 2010-03-04  
很不错,断言没用过,事务处理方式没用过
29 楼 fantasy 2010-03-04  
linkobe 写道
像“您添加的用户名已经存在”这样的业务异常,是以状态码的形式返回好呢,还是以抛异常的形式返回好呢。

貌似这个问题曾经也是一个争得你死我活的问题,有人认为抛异常的方式浪费系统资源,影响性能,有人认为异常是符合对象编程的行为方式,而不应该再回到过去那种返回状态码的原始c编程形式。两种方式当然各有利弊,LZ你能凭你4年的经验告诉我一个准备有效的方案吗

假如不用性能工具,我们一般会用80%的时间来调整20%的性能,意思说有些性能问题是写代码的时候可以暂时忽略。
另外我认为应该使用状态码,举一个例子,工单系统需要对外提供“派发工单”的接口,这种接口一般是提供给外部系统使用的,如何处理,应该由调用方自己决定,本系统只要在接口文档里详细描述每一个状态码所代表的意义即可。
另外也衍生一个话题,即数据和展现的分层,我们写代码的时候应该将数据和展现分离,如Action只提供数据(如JSON数据),至于客户端(C,HTML,JAVA,.net)如何展现他们自己决定。


28 楼 superheizai 2010-03-04  
期待楼主的精彩后续!
27 楼 li445970924 2010-03-04  
挺好的  断言没怎么用过...断言 和 if  那个效率好啊
26 楼 zhonggeneral 2010-03-04  
楼主要上岸了
25 楼 超级潜水艇 2010-03-04  
服务层异常全抛运行时异常,你这个也忒诡异了吧
24 楼 quxiaoyong 2010-03-04  
感谢楼主让我学到了不少东西,尤其SERVICE层异常处理的方式,以前从来没想过用ENUM来标示。BTW,我还没毕业,做的系统还比较少好。希望这里的高手们多写点技术经验,感谢极了。。
23 楼 treblesoftware 2010-03-03  
很赞。不过,一般来说,SERVICE可预测性太少。除了细节问题,更多的是由于业务问题导致的编程困难。
22 楼 nishizhutou 2010-03-03  
linkobe 写道
像“您添加的用户名已经存在”这样的业务异常,是以状态码的形式返回好呢,还是以抛异常的形式返回好呢。

貌似这个问题曾经也是一个争得你死我活的问题,有人认为抛异常的方式浪费系统资源,影响性能,有人认为异常是符合对象编程的行为方式,而不应该再回到过去那种返回状态码的原始c编程形式。两种方式当然各有利弊,LZ你能凭你4年的经验告诉我一个准备有效的方案吗


我们现在是层内部函数调用都是采用返回一个非0的code.
但是层与层之间采用抛出业务异常exception,然后带不同的code.上层在捕获异常后先检查"特别"code(具体哪些code需要特别处理,可配置),否则就按统一的异常处理.
但是这样也有个很严重的问题,就是有时候仅仅一个code不足与提供整个错误的环境,所以在exception中不但要带一个code,还有一个Object的参数.当有需要的时候,由下层提供必要环境对象,上层再根据约定将该对象转型后使用.这种情况虽然很少,但是很恶心.
求达人讲讲这方面比较好的实践.
21 楼 linkobe 2010-03-03  
像“您添加的用户名已经存在”这样的业务异常,是以状态码的形式返回好呢,还是以抛异常的形式返回好呢。

貌似这个问题曾经也是一个争得你死我活的问题,有人认为抛异常的方式浪费系统资源,影响性能,有人认为异常是符合对象编程的行为方式,而不应该再回到过去那种返回状态码的原始c编程形式。两种方式当然各有利弊,LZ你能凭你4年的经验告诉我一个准备有效的方案吗
20 楼 Hyphoon 2010-03-03  
对于一个不是很大的系统, 异常信息用“魔术数字般”的错误代码就是自找麻烦, 楼主用枚举的好处是既有代码提示, 又有编译检查。 后续结合Property文件, 做异常提示的国际化应该很省功夫。
19 楼 mlw2000 2010-03-03  
fantasy 写道
jansel 写道
国际化和异常有直接的关系吗?

非要搞一个标识放在异常里面,然后拿着这个标识去找一条国际化信息。

这个依赖是反的,个人觉得应该是国际化要考虑异常,如果发生这种异常了应该展示什么信息。而不是设计异常的时候就已经考虑了国际化。

你很有见地。
但是能否仔细阅读下我的文章,并认真思考下呢?

fantasy已经在代码里这么实现了,只不过加强版的errorCode
fantasy 写道

在Service里抛出:throw new FriendlyCodeRuntimeException(ErrorCode.User_Not_Repeat);

其实我们回想在用一些大型软件时,系统错误提示中总有看到类似“错误代码:XXX”
18 楼 fantasy 2010-03-03  
jansel 写道
国际化和异常有直接的关系吗?

非要搞一个标识放在异常里面,然后拿着这个标识去找一条国际化信息。

这个依赖是反的,个人觉得应该是国际化要考虑异常,如果发生这种异常了应该展示什么信息。而不是设计异常的时候就已经考虑了国际化。

你很有见地。
但是能否仔细阅读下我的文章,并认真思考下呢?
17 楼 fantasy 2010-03-03  
vieri122 写道
fantasy 写道
yuanyi_wang 写道
4年就告别研发啊??

因为工作原因,转到产品部了。

产品部就不用管研发了吗?
前期的需求,架构什么的是由产品部来做吧?这个应该也算研发。

我指的是以后写代码会非常少,最多可能是做些DEMO。
当然需求和架构是由产品部来做。
16 楼 vieri122 2010-03-03  
fantasy 写道
yuanyi_wang 写道
4年就告别研发啊??

因为工作原因,转到产品部了。

产品部就不用管研发了吗?
前期的需求,架构什么的是由产品部来做吧?这个应该也算研发。
15 楼 jansel 2010-03-03  
国际化和异常有直接的关系吗?

非要搞一个标识放在异常里面,然后拿着这个标识去找一条国际化信息。

这个依赖是反的,个人觉得应该是国际化要考虑异常,如果发生这种异常了应该展示什么信息。而不是设计异常的时候就已经考虑了国际化。
14 楼 zozoh 2010-03-03  
抛出异常的爱 写道
用回调来管理事务....
逻辑一多....
几乎想死.


把逻辑封在 几个函数里
13 楼 lzmhehe 2010-03-03  
抛开国际化不谈,我看不到使用ErrorCode 的任何好处

相关推荐

    asp.net写的web service例子

    ASP.NET Web Service是一种基于.NET Framework的简单方法,用于构建可跨平台、跨语言通信的Web应用程序。这个例子是为初学者设计的,旨在演示如何创建和使用Web Service,以及如何在ASP.NET环境中调用这些服务。 ...

    Centos7-Systemd-Service自定义编写Service应用服务配置说明整理.docx

    环境文件的路径通常为 `/usr/lib/systemd/system/&lt;service_name&gt;.service.d/environment.conf`。 CentOS 7 的 systemd 服务提供了强大的自定义配置功能,允许用户根据需要定义服务的配置信息。通过编写服务配置文件...

    Service向Activity传值(kotlin)

    在Android应用开发中,Service和Activity是两个非常重要的组件。Service用于在后台执行长时间运行的任务,而Activity则负责用户界面交互。在某些场景下,我们可能需要Service与Activity之间进行数据传递,例如本例中...

    自己写的service及调用

    这里我们关注的是"自己写的service及调用",这个话题涉及到Web服务(Web Service)的概念、Eclipse IDE的使用以及Java编程语言的应用。Web服务允许不同应用程序之间的数据交换,通常基于开放标准如XML、SOAP和WSDL,...

    Service 的基础使用方法

    在Android开发中,Service是四大组件之一,它用于在后台执行长时间运行的操作,不与用户交互。本教程将深入探讨Service的基础使用方法,适合初学者掌握。 首先,我们需要理解Service的基本概念。Service并非一个...

    Python编写Windows Service服务程序

    ### Python编写Windows Service服务程序详解 #### 一、引言 在Windows环境下,有时我们需要创建一个后台服务程序,这类程序可以在系统启动时自动运行,并在后台持续运行而不会占用用户的桌面资源。对于开发者来说...

    文件系统账户权限迁(NETWORK SERVICE)

    在windows文件服务器之间拷贝文件时,由NETWORK SERVICE账户权限控制的文件或文件夹在复制粘帖时会出现账户权限丢失的问题。次工具则是对该账户权限查找并设置相应的文件或文件夹。 W3WP.exe所使用的账户为NETWORK ...

    安卓Service学习小程序

    例如,在一个Activity中,你可以这样写: ```java Intent intent = new Intent(this, MyService.class); startService(intent); ``` 这将启动名为`MyService`的服务。一旦启动,Service会经历其生命周期的...

    Android基础 Service

    在Android系统中,Service是四大组件之一,它与Activity、BroadcastReceiver和ContentProvider共同构成了Android应用的核心架构。Service主要用于在后台执行长时间运行的操作,而无需与用户交互。它不同于线程,...

    Android 双进程守护service

    它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着...反正我是信了,demo在此,欢迎指正,很少写博客,就这样吧~~~~~~~忙去了

    mysql 5.7.x 所需mysqld.service文件

    mysql 5.7.x 所需mysqld.service文件

    service使用及发送通知

    在Android开发中,`Service` 是一个非常关键的组件,它允许应用程序在后台长时间运行操作,即使用户没有与应用交互。`Service` 主要用于执行长时间运行的任务,如播放音乐、处理网络请求或定期同步数据。本教程将...

    Android Service的startService

    在Android应用开发中,`Service` 是一个非常重要的组件,它允许应用程序在后台长时间运行操作,即使用户没有与应用程序交互。本篇文章将深入探讨 `startService()` 方法的使用及其在实际案例中的应用。 ### 一、...

    Andriod启动Service定时向服务发送请求(自己写),并震动

    该工程是花了大半天时间查阅相关资料之后,在找到一个老外的demo基础上修改的,...包中并没有写访问服务端部分,这个有点累赘,和我们普通的http请求没有区别. 至于震动,铃声类的,看了下文档,都很简单,象征性的做了一下.

    Android服务Service_详解文档

    在Android应用开发中,`Service`是一个至关重要的组件,它允许开发者在后台执行长时间运行的操作,即使用户已经离开应用程序的界面。本篇文章将深入解析`Service`的工作原理、使用场景、启动方式以及生命周期,帮助...

    QtService 实现Qt后台服务程序

    QtService是一个用于实现windows服务或unix守护进程的开源项目,下载地址 本文使用QtService演示如何实现一个windows下的后台进程,可用于一些简单的windows服务程序中。 博客介绍:...

    一次性生成dao和service层

    只需配合一下vo包名即可生成所有的vo 的dao 和service (当然,您的框架和我不一样只需要改下模板文件即可).本人也是学生,马上毕业了.写完这个以后,我非常深刻的理解这些框架的实现.也非常适合新手学习.附上源文件.

    android service实例

    在Android系统中,Service是一种非常重要的组件,它允许应用程序在后台长时间运行,即使用户与应用程序的界面没有任何交互。本篇文章将深入探讨`Android Service`的实例,帮助开发者更好地理解和运用这一核心功能。 ...

    Action,Service和Dao功能

    在不分层的系统中,我们可以将所有的代码都写到一个地方,比如 Struts 的 Action 类。在这里,我们不仅要处理页面逻辑,还要做业务逻辑,还要做数据访问。为了更好地理解和分离 Action、Service 和 Dao 的功能,我们...

    visual c++ vc编写windows service服务 源程序.zip

    在本文中,我们将深入探讨如何使用Visual C++ (VC++) 编写Windows Service服务,并结合提供的源程序进行分析。Windows Service是一种特殊的后台应用程序,它在没有用户界面的情况下运行,通常用于执行系统级任务,如...

Global site tag (gtag.js) - Google Analytics