大家好,欢迎来到IT知识分享网。
今天和同事 聊了下异常 相关的事,整理在此
目前公司中使用的 自定义异常是 extend RuntimeException
继承异常
我们在业务开发中 继承异常是extend RuntimeException 还是 Exception呢
一想 这肯定是 RuntimeException 啊,但是这是为什么呢? 选择 Exception 不行么?
RuntimeException和Exception区别
聊这个之前 我们需要确定我们的需求是什么
需求
需求是 自定义一个 业务中使用的异常
确定了需求 接下来我们就要分析
![业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?插图1 业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?](https://yundeesoft.com/wp-content/uploads/2022/11/2022112316405970.jpg)
到这里 知道 我们业务开发 基本都是运行时异常 所以用 RuntimeException
到这里有一个疑问,我们平时 IO操作的时候 动不动就爆红 让我们throws 或者 try catch,是哪个属性做到的?
首先看一段代码
![业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?插图3 业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?](https://yundeesoft.com/wp-content/uploads/2022/11/2022112316405970.jpg)
但是这个异常是因为createNewFile 方法 主动抛出的异常 和 是不是 RuntimeException 没关系啊
public boolean createNewFile() throws IOException {
SecurityManager security = System.getSecurityManager();
if (security != null) security.checkWrite(path);
if (isInvalid()) {
throw new IOException("Invalid file path");
}
return fs.createFileExclusively(path);
}
复制代码
是有关系的,非RuntimeException 都是需要throws 或者try catch 但是这个不是自动的,是开发人员写代码的时候 需要做的,代表这个异常是 必须被检查的
而其他需要注意的 引用 程序设计语言原理 书中 第434页的一部分
![业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?插图5 业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?](https://yundeesoft.com/wp-content/uploads/2022/11/2022112316405970.jpg)
这块对于业务中使用哪个 先留一个疑问 往下看
![业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?插图7 业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?](https://yundeesoft.com/wp-content/uploads/2022/11/2022112316405970.jpg)
怎么才算其他RuntimeException 代码上有什么区别?
没有区别就是一个继承 RuntimeException,另一个继承 Exception,别的没有了
事务中拦截异常
我们到这 知道了继承异常应该用RuntimeException,但是我们应该知道 阿里规约手册 中有这么一段
1、让检查异常也回滚:你就需要在整个方法前加上@Transactional(rollbackFor=Exception.class)
2、让非检查异常不回滚:
需要加入@Transactional(notRollbackFor=RunTimeException.class)
3、不需要事务管理(or 日志丢失)
需要加入@Transactional(propagation=Propagation.NOT_SUPPORTED)
为什么?
Exception类下面除了runtimeException还有SQLException和ioException
如果方法没有抛出runtimeException 而是抛出 SQLException和ioException那么事务是不会回滚的
那么这就结束了吗?在我们编码过程中,如果方法要抛出一些可检查异常时是需要throws进行显式指定异常类的
那么问题来了,我们都知道方法签名中默认是throws RuntimeException,已知SqlException不是RuntimeException的子类
小总结
@Transactional(notRollbackFor=RunTimeException.class) 是因为抛弃了 IO异常和 SQL异常等情况,所以 我们 应该用 Transactional(rollbackFor=Exception.class)
为什么 不是 rollbackFor = Throwable.class 呢
不需要显式指定 rollbackFor = Throwable.class ,因为如果发生错误,spring将默认回滚事务。**
原本就是除了 非RuntimeException 别的已经在事务管理中了
在其默认配置中,Spring Framework的事务基础结构代码仅标记事务对于运行时回滚,未经检查的异常;也就是说,抛出的异常是RuntimeException的实例或子类。 (错误也会 – 默认情况下会导致回滚) 。从事务方法抛出的已检查异常不会导致在默认配置中回滚。**
或者查看 DefaultTransactionAttribute
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
复制代码
具体位置 docs.spring.io/spring-fram…
总结下来事务方面应该使用 @Transactional(rollbackFor=Exception.class)
其他中间件 对异常的应用场景 和 为什么?
先看nacos
//检查 异常
public class NacosException extends Exception {
}
复制代码
在使用的时候
![业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?插图9 业务中 自定义异常用 Exception 还是 RuntimeException? 为什么?](https://yundeesoft.com/wp-content/uploads/2022/11/2022112316405970.jpg)
有throws 的 也有 try catch的
那么 是什么抛出Nacos 异常的呢?
private <T extends Response> T requestToServer(AbstractNamingRequest request, Class<T> responseClass)
throws NacosException {
try {
xxx
} catch (Exception e) {
throw new NacosException(NacosException.SERVER_ERROR, "Request nacos server failed: ", e);
}
throw new NacosException(NacosException.SERVER_ERROR, "Server return invalid response");
}
复制代码
rocketmq
先看一个 运行时异常
运行时异常
public class AclException extends RuntimeException {
}
复制代码
使用
public static void verify(String netaddress, int index) {
if (!AclUtils.isScope(netaddress, index)) {
//运行的时候 发生异常
throw new AclException(String.format("Netaddress examine scope Exception netaddress is %s", netaddress));
}
}
复制代码
再看一个 检查异常
public class MQClientException extends Exception {
}
复制代码
throws MQClientException, RemotingException, MQBrokerException
复制代码
使用
public TransactionSendResult sendMessageInTransaction(final Message msg,
final LocalTransactionExecuter localTransactionExecuter, final Object arg)
throws MQClientException {
TransactionListener transactionListener = getCheckListener();
if (null == localTransactionExecuter && null == transactionListener) {
//如果为空 client 异常
throw new MQClientException("tranExecutor is null", null);
}
}
复制代码
总结
中间件中大部分都是 client 连接失败,远程连接超时,server端异常 这种,属于检查时异常,所以应该 extend Exception
但是
- 业务开发的时候 大部分都是 判断空,属于运行时异常 推荐 RunntimeException
- 检查时异常 需要一直 throws,从代码整洁度上 推荐 RunntimeException
总结
- 远程连接的使用 / 异常 使用检查时异常,让另一端能感受到异常
- 业务中的代码使用 运行时异常
我还是推荐业务使用 extends RuntimeException,其余的就需要根据业务场景选择了
思考
ok 那你说 远程连接使用 检查时异常,那feign 属于远程rpc,他的异常就必须是 检查时异常么?为什么?
链接:https://juejin.cn/post/7166976169152086024
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/13102.html