我爱oo,我爱java

交流blog QQ:421057986 oofrank@donews

Spring 中的异常悖论

这个题目可能有些危言悚听,使用Spring的同行不用害怕,只是因为工作中碰到一些问题,才偶然想到这个问题。

首先要明确两个问题:
1、系统隔离原则:
    即系统间依赖应该是清晰的,不因为一个系统的故障影响其他系统,甚至整个系统。
2、简单应用习惯:
    普通程序员只会处理checked Exception,负责任的程序员会处理被调用的函数可能抛出的异常(根据源码或javadoc)
 

我们碰到一个情况:
使用Spring的 init 特性初试化一个bean--一个使用Qutarz的调度程序。初试化过程中会抛出RuntimeException,从而造成Spring容器的整个初试化失败。首先我们修改了程序,捕获了所有异常,随后在编码指南中加入了一句话:"所有使用Spring-init机制初试化的类必须在init中捕获所有异常:Exception"。因为只有如此才能保证整个系统不会因为局部问题而完全瘫痪。

我觉得这是Spring对异常处理的一个悖论:
正方:底层异常都封装成Runtime的,经过几次包装--->简单应用习惯--->异常被抛出领域层(init场景下:由Spring处理)
反方: 一个类的失败可以造成整个系统的失败---->Spring被RuntimeException宕掉---->不符合系统隔离原则


当然充分的测试可能可以解决这个问题:但是要注意,测试只能证明系统有bug,不能证明系统没有bug。

解决方案:
1、好的设计习惯:将应该隔离的系统隔离开-->使用不同的Spring配置文件.
2、接口层错误处理:在接口层应该尽量对可以处理的异常进行处理,然后以合理的方式传递给上层.


PS:在与人交互的系统中都应该给最终用户合理的错误提示,所以表现层应该尽量捕获非业务的RuntimeException给最终用户更好的操作感受。

posted on 2006-01-19 21:45 兼听则明 阅读(1442) 评论(19)  编辑  收藏 所属分类: java

评论

# re: Spring 中的异常悖论 2006-01-20 08:54 darkbluefeeling

我觉得初始化如果都出问题了,系统就应该halt了,把问题隐藏起来可比暴露出来问题多的多。毕竟是初始化,这儿不应该出问题的。  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 08:59 王麻子

不是表现层应该尽量捕获非业务的RuntimeException给最终用户更好的操作感受,,
而是业务逻辑层根据业务需求抛出一系列的应用异常.
如果表现层遇到了非应用异常的其它情况,就是编程错误,或系统错误.  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 10:05 qiu

测试只能证明系统有bug,不能证明系统没有bug。


不是应该感谢spring帮你找到了一个bug么?

  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 10:25 兼听则明

to: darkbluefeeling
当然,如果重要的系统部分不能init成功,系统应该首先排错;但如果只是很小的一个部分不能init成功--就造成系统不能启动,我认为是系统设计有问题。
比如:如果声卡驱动装载不成功,操作系统就不能启动,只是 "兰屏",你将大骂操作系统,而如果硬盘有故障,操作系统不能引导,则是骂不到操作系统。  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 10:34 兼听则明

to: 王麻子
我觉得你说的是对的,但是有时候需求并没有分析完全,在系统上线后才发生这个问题,即本该是“业务需求抛出一系列的应用异常.”但实际抛出了RuntimeException,我认为同样不该展现给客户“异样”的异常:
例:----仅仅是例子!
我使用Qutarz作调度,当一个调度不能被fire时,它将抛出RuntimeException,我们的测试(案例)没有发现这个情况,到系统上线时,抛出异常,如果随便给客户一个"系统错误",我认为是很不好的,因为客户会认为发生了很严重的错误,实际只是简单的输入错误而已,即按年调度,但在开始时间到结束时间端内没有该调度触发的时机。
  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 10:39 兼听则明

to qiu:
然,Spring帮我捉了一只虫,
你是否感谢MS帮你捉了 其他软件的虫呢 --------写了半天帖子---系统崩溃,没能保存----
在没有上线时,触发bug非常好!可是如果系统正式运行时发生的瘫痪级异常,作为软件开发者还会笑的出来吗?
---显然,使用某种通知机制通知管理员,由管理员来需求开发人员支持,好过使用系统宕掉的方式通知软件开发者....  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 10:40 yuxie

Road从来没有说过底层异常都封装成Runtime的,他的意思是不能被恢复的异常你要做成Runtime的(one-on-one那本书),像这个task的初始化,你捕捉了有什么用呢?异常还是已经发生了,而且没有被恢复!  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 11:20 兼听则明

to: yuxie

实际我都捕获了,并忽略了----忽略也是一种“你说的恢复”,另外“不能被恢复的异常你要做成Runtime的”的问题在于现在Spring中把所有的异常都封装成Runtime的了----当然,我们还可以通过捕获处理我们想处理的问题。  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 11:20 pesome

不能恢复就一定要做成runtime exception?without ejb还说checked exception可以替代返回值呢。要具体问题具体分析,不能太教条。  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 11:23 兼听则明

在充分设计和充分测试的情况下,这个问题可以被控制到很小的范围,但是谁能保证设计和测试足够"充分"呢?  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 11:44 兼听则明

checked exception可以替代返回值::确实如此,实际上业务异常是以返回值的身份出现的,更不该是"异常",比如login()方法可能抛出 UnknownUserException,WrongPasswordException....
而 addUser() 可以抛出UserExistException 比 主键冲突的 DataAccessException好的多.  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 12:50 yuxie

关于返回值得问题,我认为抛出Checked Exception作为返回值是业务层的事情,而我们说的底层的应用,是需要跟业务层松耦合的。如果底层(集成层等)抛出一个checked exception,你的业务逻辑层就必须要捕获它或者throw掉,这就增加了系统的耦合性。所以spring把大部分异常封装成runtime是有道理的。如果他不做成runtime的,你的业务层就必须import org.springframework.…….XXException,紧绑定在spring上,岂不是很郁闷!  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 13:42 兼听则明

to yuxie:
你说的很对,Spring最好不要侵入我们的领域。

但对于 “addUser() 可以抛出UserExistException 比 主键冲突的 DataAccessException好的多” 问题,我们怎样才能处理到底是数据库连接异常,还是仅仅是重复UserID的输入错误(即主键冲突--业务主键)呢?  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 13:50 pesome

spring设计成runtime是合理的,而我们catch它的异常也是合理的  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 15:26 yuxie

to 兼听则明:
很简单亚,你只要做一个checkUserExist()的方法就是了,如果返回true就throw exception。通过catch DataAccessException来判断是否用重复记录,我觉得不是一个好的方法。
数据库一旦发生异常,抛出DataAccessException,就应该是一个非常严重的错误,此时系统已无法正常使用,直接在表现层总的catch一下,给用户一个错误界面就ok了。
如果在checkUserExist()之后,两个用户同时插了相同的数据,这确实是个问题~欧没有想到好的方法  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 15:33 兼听则明

to yuxie:
如果数据库记录很多,checkUserExist(),成本很高,另外,如果有并发冲突时checkUserExist()将很可能失效。--如你所说!  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 15:47 pesome

抛出DataAccessException也不一定是非常严重的问题,更不表示系统已无法正常使用。说到底,先check还是抛错都是由成本决定,由出错的几率决定。  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-20 17:24 兼听则明

to pesome:
同意  回复  更多评论   

# re: Spring 中的异常悖论 2006-01-21 17:14 yuxie

dao层try一下,如果是有重复记录,就抛出checked exception(dao层公用的),业务层捕获即可。  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: