前段时间在调试项目中某个功能的时候,由于是在测试环境中,所以在通过RPC框架调用某个远程服务获取相关信息的时候,抛出了一个UndeclaredThrowableException。JDK的java doc是这么解释UndeclaredThrowableException的:如果代理实例的调用处理程序的 invoke 方法抛出一个经过检查的异常(不可分配给 RuntimeException 或 Error 的 Throwable),且该异常不可分配给该方法的throws子局声明的任何异常类,则由代理实例上的方法调用抛出此异常。
明白了什么是UndeclaredThrowableException后,那我就查我的代码中时什么原因导致了这个exception,最后查到是RPC client在调用远程服务的时候,因为测试环境不稳定,等待超时,抛出了一个TimeOutException,而这个TimeOutException不是业务方法所声明的异常,因此就被包装成UndeclaredThrowableException抛出了。这是一个RuntimeException,RPC框架及我的应用(我看了下公司相关项目的代码,也基本都没有处理这个RuntimeException)都没有处理这个异常,那么如果是一个Web项目,这个异常会被容器捕捉到,并给用户展示出一个容器缺省的错误页面,并抛一个500的server错误,如下图所示:
这样的页面展示给用户看,即不友好也不专业/:^_^。那我就想在什么地方可以处理这个异常,然后进行相关处理呢?就上面这个例子来看,这个异常总共途径了一下几个系统:
RPC client(源头)--->我的应用---->Web容器(容器层)
那么我们来分析下,分别在那一层处理这个异常比较合适。
1、源头RPC client层:我认为,判断一处代码是应该处理异常还是将异常抛出,取决于其是否获取了异常信息后,能如何应对?如果其能针对捕捉到的异常做出符合业务逻辑需要的处理,那么就不应该讲异常继续抛出,反之,则抛出异常。比如上面的TimeOutException,不同应用的业务逻辑有不同的处理办法,而RPC Client端并不知道这个具体的情况,所以RPC Client不需要处理这类异常,将其继续抛出即可。越接近异常的源头,处理异常最方便(此处的方便,指的是,在接近于源头的底层框架处理异常,那么对调用这些框架的应用代码来说,就不需要关注异常处理了,这就方便了)
2、应用层:那么是不是需要在应用层做处理呢?这里需要具体情况具体分析。拿我这个应用来说,这是一个web应用,就算我这个应用对runtimeException不做处理,web容器也会对这个异常进行处理,并不会造成程序的崩溃。但是如果应用层不是web项目,或者应用不是依托在某个容器内,那如果应用层不对这个异常进行处理的话,就没人处理这个异常了,就会直接抛出一个RuntimeException,导致程序挂掉。因此我认为,如果我们在应用中调用RPC等之类的服务,要注意一下几点:
a)此处的调用抛了UndeclaredThrowableException,需要额外的处理不?
b) 如果需要,就要在此处捕捉到这个异常;
c) 如果不需要,那么就要想想,我们的应用把这个异常抛出去,接下来会不会有地方来处理这个异常,如果有,则可以继续抛出?
d)如果我们的应用已经是异常处理链中的最后一环,那么还是要把这个异常捕捉住。
e)如果有Web容器之类的罩着,我们可以把这个异常继续传递下去。
如果在应用中要处理异常,应该考虑的全面细致。是否需要降级?该流程是否是必须流程,如果是必须流程是否还会涉及到业务回滚,如果是非必须流程如何在产生异常时不影响当前业务。是否需要容灾?尤其是在电子商务和金融方面,异常的产生是否需要保持财务信息的清晰正常。即使发生不可控异常,支出与收入信息是否可控,不因异常导致非正常的支出与收入等待。
3、Web容器:上面说了,如果是Web项目,容器会处理应用抛出的RuntimeException,就像上面图展示的JBoss Web容器的默认Error页面。但是这样的页面实在是太丑陋了,很不专业。/:^_^。因此我们需要告诉Web容器,当出现某某错误的时候,就展示相应的我们准备好的相应的错误页面。我们只要通过下面的简单配置就可以让Web容器显示漂亮的错误页面:
<error-page>
<error-code>500</error-code>
<location>/error.vm</location>
</error-page>
另外,
对于RPC之类等涉及网络的服务调用,肯定会存在不同情况的异常,开发人员如果不考虑这个的话,那就不知道会出现多少问题,那就是一个不好的编程习惯。
异常的处理是个大学问啊. /:^_^。记录一下,以便以后查看
- 大小: 14.4 KB
分享到:
相关推荐
具体来说,`unthrow`方法接收一个`Runnable`对象,这个对象通常代表Lambda表达式,然后在运行时捕获任何可能抛出的检查异常,并包装成`UndeclaredThrowableException`(一个未检查异常)再次抛出。这样,即使Lambda...
SessionBean: Stateless Session Bean 的生命周期是由容器决定的,当客户机发出请求要建立一个Bean的实例时,EJB容器不一定要创建一个新的Bean的实例供客户机调用,而是随便找一个现有的实例提供给客户机。...
* pageContext 对象:表示一个 javax.servlet.jsp.PageContext 对象,提供了对各种范围的名字空间、servlet 相关的对象的 API 和通用的 servlet 相关功能的方法。 * session 对象:表示一个请求的 javax.servlet....
在使用Java动态代理时出现了一个很棘手的问题,实现类里抛出了一个自定义异常,但外面捕获不到。 虽然使用 printStack 可以输出调试信息,但通过 getMessage 获取不到提示,因为项目需求是捕捉到同一种自定义异常...
例如,当一个变量被声明为final时,则该变量不能重新赋值;如果是一个对象变量,则对象引用不能改变,但对象内容可以修改。 - **finally**: 通常与try-catch语句配合使用,在finally块中的代码无论是否有异常发生...
同样地,如果一个变量被声明为 final,则其值不能被改变(对于对象而言,是指向该对象的引用不能改变,但对象本身的状态可以改变)。 - **finally**: “finally”块与 try-catch 结构紧密关联,用于确保无论是否发生...
用户在支付时,系统会生成一个一次性付款码,这个码只能在指定时间内有效,且每笔交易后都会更新,确保了交易的安全性。 4. 安全注意事项: - 共享密钥K必须保密,不能泄露给任何未经授权的实体。 - 时间同步需要...