我的编程空间,编程开发者的网络收藏夹
学习永远不晚

nacos+springboot+dubbo2.7.3统一处理异常的方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

nacos+springboot+dubbo2.7.3统一处理异常的方法

这篇“nacos+springboot+dubbo2.7.3统一处理异常的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“nacos+springboot+dubbo2.7.3统一处理异常的方法”文章吧。

1. 为什么要抛异常?

不同开发团队间便于追溯异常的来源以及为了便于定位问题的需要

往往实际开发中的架构是这么一个样子的:

nacos+springboot+dubbo2.7.3统一处理异常的方法

dubbo微服务架构简图

不同层的开发人员都是不同的人或者是不同的几波人马;

无状态的API层(一组Tomcat对Nginx Web层的API暴露)是一组开发团队;

微服务Dubbo层是另一组开发团队;

在调试、测试、上线后我们经常会发生各种Exception,此时这几个不同的开发团队间会互相扯皮、打架,并且大家都要忙于定位这个Exception到底是发生在哪一层,甚至需要追溯Exception发生在哪个点(stackTrace)。

Service层有数据库事务一致性的问题必须抛出异常

我们都知道在spring中的Service层必须抛出Runtime Exception,否则Service层的方法如果有涉及数据库的修改操作是不会回滚的。

2. 给出解决方案

其实解决方案真正的无外乎就2种:

  • provider向远程consumer层直接抛RuntimeException即可;

  • provider端把所有的Exception进行统一包装,向consumer端返回json报文体的类似message:xxx,code:500,data{xxx:xxx,xxx:xxx}这样的消息而在provider端进行“logger.error”的记录即可;

本文把这2种实现方式都给实现了,下面开始直接show me the code的方式来说话吧。

3. 两种抛异常的实例解说

环境搭建

nacos1.1.4

我们这边不用dubbo admin,因为dubbo admin太老且使用不方便,缺少了很多管理微服务所需要的基本功能。并且dubbo从2.6开始已经把dubbo admin从它的主工程里分离了出去,同时dubbo2.6开始支持nacos registry了。

目前来说nacos是最方便、效率最高、功能最强大的微服务发现组件(甚至支持spring cloud)。

下载地址在这里(请戳):阿里nacos最新下载地址

下载后直接解压,然后进行nacos配置

nacos+springboot+dubbo2.7.3统一处理异常的方法

编辑这个application.properties文件,我们把nacos自动服务发现管理端连上自己开发环境上的mysql

# springspring.datasource.platform=mysqlserver.contextPath=/nacosserver.servlet.contextPath=/nacosserver.port=8848db.num=1db.url.0=jdbc:mysql://192.168.56.101:3306/nacos?useUnicode=true&characterEncoding=utf-8&useSSL=falsedb.user=nacosdb.password=111111

配完后直接双击:startup.cmd启动nacos

nacos+springboot+dubbo2.7.3统一处理异常的方法

登录界面中使用nacos/nacos即可进行登录了。

nacos+springboot+dubbo2.7.3统一处理异常的方法

登录后看到nacos管理界面就说明nacos配置和启动成功了。接下来我们就要开始书写dubbo的provider端与consumer端了。

dubbo工程搭建

nacos-parent工程

整个工程我已经放在git上了,地址请戳这里:nacos-dubbo-demo

工程的依赖结构如下:

nacos+springboot+dubbo2.7.3统一处理异常的方法

由于dubbo与springboot结合的项目不多,很多网上有的博客也充斥着乱抄、自己都没有验证过就上代码的,因此大多网友们通过网上之言片语拼凑起来的项目在本地很难运行起来,不是maven包冲突就是少这个、那个包。下面给出工程的parent pom文件。

nacos+springboot+dubbo2.7.3统一处理异常的方法

<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.sky.demo</groupId><artifactId>nacos-parent</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><description>Demo project for Spring Boot Dubbo Nacos</description><modules></modules> <properties><java.version>1.8</java.version><spring-boot.version>1.5.15.RELEASE</spring-boot.version><dubbo.version>2.7.3</dubbo.version><curator-framework.version>4.0.1</curator-framework.version><curator-recipes.version>2.8.0</curator-recipes.version><druid.version>1.1.20</druid.version><guava.version>27.0.1-jre</guava.version><fastjson.version>1.2.59</fastjson.version><dubbo-registry-nacos.version>2.7.3</dubbo-registry-nacos.version><nacos-client.version>1.1.4</nacos-client.version><mysql-connector-java.version>5.1.46</mysql-connector-java.version><disruptor.version>3.4.2</disruptor.version><aspectj.version>1.8.13</aspectj.version><nacos-service.version>0.0.1-SNAPSHOT</nacos-service.version><skycommon.version>0.0.1-SNAPSHOT</skycommon.version><maven.compiler.source>${java.version}</maven.compiler.source><maven.compiler.target>${java.version}</maven.compiler.target><compiler.plugin.version>3.8.1</compiler.plugin.version><war.plugin.version>3.2.3</war.plugin.version><jar.plugin.version>3.1.2</jar.plugin.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>${dubbo.version}</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId><version>${dubbo.version}</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>${curator-framework.version}</version></dependency> <dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>${curator-recipes.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql-connector-java.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>${disruptor.version}</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>${guava.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-nacos</artifactId><version>${dubbo-registry-nacos.version}</version></dependency><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId><version>${nacos-client.version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>${aspectj.version}</version></dependency> </dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>${compiler.plugin.version}</version><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>${war.plugin.version}</version></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>${jar.plugin.version}</version></plugin></plugins></build></project>

演示用数据库(mySQL5.7)建表语句

CREATE TABLE `t_product` (  `product_id` int(11) NOT NULL AUTO_INCREMENT,  `product_name` varchar(45) DEFAULT NULL,  PRIMARY KEY (`product_id`));CREATE TABLE `t_stock` (  `stock_id` int(11) NOT NULL AUTO_INCREMENT,  `stock` int(11) DEFAULT NULL,  `product_id` int(11) NOT NULL,  PRIMARY KEY (`stock_id`));

它建了两张表,t_product表和t_stock表。这两张表我们会用于演示dubbo provider中对于数据库一致性插入时在碰到Exception时怎么处理回滚的场景。

nacos-service工程搭建说明

先上pom.xml(很重要,这里面的依赖是正确的springboot+dubbo+nacos客户端的完整配置)

<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.sky.demo</groupId><artifactId>nacos-service</artifactId><version>0.0.1-SNAPSHOT</version><name>nacos-service</name><description>服务者 Demo project for Spring Boot dubbo nacos</description><parent><groupId>org.sky.demo</groupId><artifactId>nacos-parent</artifactId><version>0.0.1-SNAPSHOT</version></parent> <dependencies> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.spockframework</groupId><artifactId>spock-core</artifactId><scope>test</scope></dependency><dependency><groupId>org.spockframework</groupId><artifactId>spock-spring</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></dependency> <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency><!-- Dubbo Registry Nacos --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-nacos</artifactId></dependency><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId></dependency><dependency><groupId>org.sky.demo</groupId><artifactId>skycommon</artifactId><version>${skycommon.version}</version></dependency></dependencies><build><sourceDirectory>class="lazy" data-src/main/java</sourceDirectory><testSourceDirectory>class="lazy" data-src/test/java</testSourceDirectory><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins><resources><resource><directory>class="lazy" data-src/main/resources</directory></resource><resource><directory>class="lazy" data-src/main/webapp</directory><targetPath>META-INF/resources</targetPath><includes><include>**@AfterThrowing(throwing = "exception", pointcut = "execution(* org.sky.service.*.*(..))")public void afterThrow(Throwable exception) {if (exception instanceof RuntimeException) {logger.error("DemoRpcRuntimeExceptionHandler side->exception occured: " + exception.getMessage(),exception);throw new DemoRpcRunTimeException(exception);}// logger.error("DemoRpcRuntimeExceptionHandler side->exception occured: " +// exception.getMessage(), exception);}}

开始进入核心provider Service端的制作。

ProductService接口

我们把它放置于common工程,这样consumer工程也就可以通过nacos的注册中心找到这个接口名,然后通过spring的invoke来对于远程的用于具体实现service逻辑的xxxServiceImpl类进行调用了。

package org.sky.service; import org.sky.exception.DemoRpcRunTimeException;import org.sky.platform.util.DubboResponse;import org.sky.vo.ProductVO; public interface ProductService {public DubboResponse addProductAndStock(ProductVO prod) throws DemoRpcRunTimeException;}

具体业务逻辑实现类,ProductServiceImpl

该类做这么一件事:

1)插入t_product表数据

2)插入t_stock表数据

插两张表时,只要有一点点错误那么整个插入事务回滚,否则成功。这边需要注意的就是:

  • springboot service只有接到RuntimeException才会回滚;

  • 要把RuntimeException从provider远程传递到consumer端,包括把stackTrace这些信息也远程传递到consumer端,那么这个exception必须是serializable的;

  • 暴露成dubbo provider service的service方法必须加上@Service注解,这个Service可不是spring annotation的service而是ali dubbo的service,在2.7.3开始变成了org.apache.dubbo包了。它配合着springboot的主启动文件中的@EnableDubbo来启作用,它在启动后会通过application.properties中的dubbo.scan.base-packages中所指的路径把这个路径下所有的类寻找是否带有@Service注解,如有那么就把它通过nacos-registry给注册到nacos中去;

nacos+springboot+dubbo2.7.3统一处理异常的方法

ProductServiceImpl.java

package org.sky.service; import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException; import org.apache.dubbo.config.annotation.Service;import org.sky.exception.DemoRpcRunTimeException;import org.sky.platform.util.DubboResponse;import org.sky.vo.ProductVO;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.PreparedStatementCreator;import org.springframework.jdbc.support.GeneratedKeyHolder;import org.springframework.jdbc.support.KeyHolder;import org.springframework.transaction.annotation.Transactional; @Service(version = "1.0.0", interfaceClass = ProductService.class, timeout = 120000)public class ProductServiceImpl extends BaseService implements ProductService {@AutowiredJdbcTemplate jdbcTemplate; @Override@Transactionalpublic DubboResponse<ProductVO> addProductAndStock(ProductVO prod) throws DemoRpcRunTimeException {DubboResponse<ProductVO> response = null;int newProdId = 0;String prodSql = "insert into t_product(product_name)values(?)";String stockSql = "insert into t_stock(product_id,stock)values(?,?)";try {if (prod != null) {KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() {@Overridepublic PreparedStatement createPreparedStatement(Connection connection) throws SQLException {PreparedStatement ps = connection.prepareStatement(prodSql, new String[] { "id" });ps.setString(1, prod.getProductName());return ps;}}, keyHolder);newProdId = keyHolder.getKey().intValue();logger.info("======>insert into t_product with product_id:" + newProdId);if (newProdId > 0) {jdbcTemplate.update(stockSql, newProdId, prod.getStock());logger.info("======>insert into t_stock with successful");ProductVO returnData = new ProductVO();returnData.setProductId(newProdId);returnData.setProductName(prod.getProductName());returnData.setStock(prod.getStock());response = new DubboResponse(HttpStatus.OK.value(), "success", returnData);//throw new Exception("Mk throwed exception to enforce rollback[insert into t_stock]");return response;} } else {throw new DemoRpcRunTimeException("error occured on ProductVO is null");}} catch (Exception e) {logger.error("error occured on Dubbo Service Side: " + e.getMessage(), e);throw new DemoRpcRunTimeException("error occured on Dubbo Service Side: " + e.getMessage(), e);}return response;} }

这个类目前是正常状态,我们先调用一把正常的provider到service端的过程然后接下来就来演示如何把exception远程传递到consumer端。

nacos-consumer工程搭建说明

先上pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.sky.demo</groupId><artifactId>nacos-consumer</artifactId><version>0.0.1-SNAPSHOT</version><name>nacos-service</name><description>消费者 Demo project for Spring Boot dubbo nacos</description><parent><groupId>org.sky.demo</groupId><artifactId>nacos-parent</artifactId><version>0.0.1-SNAPSHOT</version></parent>  <dependencies><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.spockframework</groupId><artifactId>spock-core</artifactId><scope>test</scope></dependency><dependency><groupId>org.spockframework</groupId><artifactId>spock-spring</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><!-- 去掉默认配置 --><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency><!-- Dubbo Registry Nacos --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-nacos</artifactId></dependency><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency><!-- import sky common package --><dependency><groupId>org.sky.demo</groupId><artifactId>skycommon</artifactId><version>${skycommon.version}</version></dependency></dependencies><build><sourceDirectory>class="lazy" data-src/main/java</sourceDirectory><testSourceDirectory>class="lazy" data-src/test/java</testSourceDirectory><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins><resources><resource><directory>class="lazy" data-src/main/resources</directory></resource><resource><directory>class="lazy" data-src/main/webapp</directory><targetPath>META-INF/resources</targetPath><includes><include>**@Pointcut(value = "execution(* org.sky.service.*.*(..))")private void servicePointcut() {} @Pointcut(value = "@annotation(org.springframework.transaction.annotation.Transactional)")private void transactionalPointcut() {} @Around("servicePointcut() && !transactionalPointcut()")public Object doAround(ProceedingJoinPoint pjp) {Object[] args = pjp.getArgs();try {return pjp.proceed();} catch (Exception e) {processException(pjp, args, e);return DubboResponse.error("exception occured on dubbo service side: " + e.getMessage());} catch (Throwable throwable) {processException(pjp, args, throwable);return DubboResponse.error("exception occured on dubbo service side: " + throwable.getMessage());}} @Around("servicePointcut() && transactionalPointcut()")public Object doTransactionalAround(ProceedingJoinPoint pjp) throws Throwable {try {return pjp.proceed();} catch (Exception e) {Object[] args = pjp.getArgs();// dubbo会将异常捕获进行打印,这里就不打印了processException(pjp, args, e);// logger.error("service with @Transactional exception occured on dubbo service// side: " + e.getMessage(), e);throw new RuntimeException(e.getMessage(), e);}} private void processException(final ProceedingJoinPoint joinPoint, final Object[] args, Throwable throwable) {String inputParam = "";if (args != null && args.length > 0) {StringBuilder sb = new StringBuilder();for (Object arg : args) {sb.append(",");sb.append(arg);}inputParam = sb.toString().substring(1);}logger.error("\n 方法: {}\n 入参: {} \n 错误信息: {}", joinPoint.toLongString(), inputParam,Throwables.getStackTraceAsString(throwable));}}

它的作用就是:

  • 把一切Exception使用一个叫DubboResponse的请求体来返回provider端的service报文;

  • 如果provider端出错,那么也把错误的系统code与系统message“包”在DubboResponse内

等等等等。。。。。。出问题了!此处还没全完,为什么?

一切Exception?这样一来那么包完后在Service层岂不是没有Exception被抛出了?如果Service方法涉及到数据库操作没有抛RuntimeException时数据库事务怎么回滚?

这才有了我们在这个handler类中有这么一段内容,它的作用就是对一切有@Transactional注解的Service方法在其出错时,还是照样要抛"RuntimeException",对于其它的就都包成DubboResponse返回给调用者了(如下对于非事务型Service方法的异常的统一包装):

@Around("servicePointcut() && !transactionalPointcut()")public Object doAround(ProceedingJoinPoint pjp) {Object[] args = pjp.getArgs();try {return pjp.proceed();} catch (Exception e) {processException(pjp, args, e);return DubboResponse.error("exception occured on dubbo service side: " + e.getMessage());} catch (Throwable throwable) {processException(pjp, args, throwable);return DubboResponse.error("exception occured on dubbo service side: " + throwable.getMessage());}}

好了,然后我们现在重新启动我们的系统,我们再来看下面的运行示例。。。。。。

等!

忘记一件事,下面我给出位于“common”工程中的ProductVO和DubboResponse这两个类的结构先,我写博文不喜欢“藏”一手。

ProductVO.java

package org.sky.vo; import java.io.Serializable; public class ProductVO implements Serializable { private int stock = 0; public int getStock() {return stock;} public void setStock(int stock) {this.stock = stock;} public String getProductName() {return productName;} public int getProductId() {return productId;} public void setProductId(int productId) {this.productId = productId;} public void setProductName(String productName) {this.productName = productName;} private int productId = 0;private String productName = "";}

DubboResponse.java

package org.sky.platform.util; import java.io.Serializable; import org.springframework.http.HttpStatus; import com.alibaba.fastjson.JSON; public class DubboResponse<T> implements Serializable {private static final long serialVersionUID = 1L; private int code; private String message; private T data; public DubboResponse(int code, String message) {this.code = code;this.message = message;} public DubboResponse(int code, String message, T data) {this.code = code;this.message = message;this.data = data;} public T getData() {return data;} public void setData(T data) {this.data = data;} public static <T> DubboResponse success(String message, T data) {String resultStr = JSON.toJSONString(data);return new DubboResponse(HttpStatus.OK.value(), message, data);} public static DubboResponse success(String message) {return success(message, null);} public static DubboResponse error(String message) {return new DubboResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null);} public static DubboResponse error(int code, String message) {return new DubboResponse(code, message, null);} public int getCode() {return code;} public void setCode(int code) {this.code = code;} public String getMessage() {return message;} public void setMessage(String message) {this.message = message;}}

“正常”据有@Transactional的Service方法抛异常演示:

现在我们把nacose-service和nacos-consumer运行起来看效果,试图插入一个新的prouct:

nacos+springboot+dubbo2.7.3统一处理异常的方法

得到返回:

nacos+springboot+dubbo2.7.3统一处理异常的方法

再来看nacos-service端、nacos-consumer端以及数据库

nacos+springboot+dubbo2.7.3统一处理异常的方法

nacos+springboot+dubbo2.7.3统一处理异常的方法

nacos+springboot+dubbo2.7.3统一处理异常的方法

nacos+springboot+dubbo2.7.3统一处理异常的方法

可以看到provider与consumer端都正确抛错且数据库中没有插进去值。

“不正常”的不含有Transactional的(普通)Service方法抛异常被封装演示:

我们现在做点小手脚,我们把provider端的“addProductAndStock(ProductVO prod)”方法上的@Transactional拿走来看看效果。

@Overridepublic DubboResponse<ProductVO> addProductAndStock(ProductVO prod) throws DemoRpcRunTimeException {DubboResponse<ProductVO> response = null;int newProdId = 0;String prodSql = "insert into t_product(product_name)values(?)";String stockSql = "insert into t_stock(product_id,stock)values(?,?)";try {if (prod != null) {KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() {@Override

请像上面这样的代码片端

我们再在nacos-consume端做一个小小的修改,如下所示,让consumer端直接把provider端组装好的{ "message" : "xxxx..."}显示在“最前端”(一切通过 nginx端来访问consumer,consumer再通过provider调用数据库,在这边我们使用的是postman)。

nacos+springboot+dubbo2.7.3统一处理异常的方法

然后我们来运行起来看一下效果:

我们可以看到,这一次在去除了@Transactional注解后,当Service方法抛错时,请求端拿到的是我们经过包装过的DubboResponse内的东西

nacos+springboot+dubbo2.7.3统一处理异常的方法

provider端包装普通Service抛出的异常的核心代码:

@Around("servicePointcut() && !transactionalPointcut()")public Object doAround(ProceedingJoinPoint pjp) {Object[] args = pjp.getArgs();try {return pjp.proceed();} catch (Exception e) {processException(pjp, args, e);return DubboResponse.error("exception occured on dubbo service side: " + e.getMessage());} catch (Throwable throwable) {processException(pjp, args, throwable);return DubboResponse.error("exception occured on dubbo service side: " + throwable.getMessage());}}

我们查看我们的Provider端,它正是通过上述代码catch(Exception e)中的这一段来进行服务端日志的记错和把错误包装后返回给到consumer端的,就是下面这两句:

processException(pjp, args, e);return DubboResponse.error("exception occured on dubbo service side: " + e.getMessage());

来看看nacos-service端的日志输出

nacos+springboot+dubbo2.7.3统一处理异常的方法

来看看nacos-consumer端的日志输出

nacos+springboot+dubbo2.7.3统一处理异常的方法

哈哈,这次nacos-consumer端无任何抛错,因为错误已经被provider端包装起来了。

当然,当我们看我们的DB端时,肯定,是有数据插入成功的。

因为前文说了,对于无@Transactional注解的方法,我们的aop handler类会把一切错误 “吃掉”,在后台仅作记录然后包成正常返回结果给到consumer端的,那么provider端的Service方法既无RuntimeException抛出,何来回滚?

当然是插入成功的!

t_product表

nacos+springboot+dubbo2.7.3统一处理异常的方法

t_stock表

nacos+springboot+dubbo2.7.3统一处理异常的方法

以上就是关于“nacos+springboot+dubbo2.7.3统一处理异常的方法”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

nacos+springboot+dubbo2.7.3统一处理异常的方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

nacos+springboot+dubbo2.7.3统一处理异常的方法

这篇“nacos+springboot+dubbo2.7.3统一处理异常的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“
2023-06-29

Springboot统一异常处理的方法是什么

Spring Boot提供了一个全局异常处理的方法,可以通过编写一个`@ControllerAdvice`注解的类来实现统一异常处理。具体步骤如下:1. 创建一个类并使用`@ControllerAdvice`注解标注,该类需要被Spring
2023-08-09

详解SpringBoot中的统一异常处理

这篇文章主要介绍了详解SpringBoot中的统一异常处理,在独立的某个地方,比如单独一个类,定义一套对各种异常的处理机制,需要的朋友可以参考下
2023-05-19

Spring异常实现统一处理的方法

这篇文章主要介绍了Spring异常实现统一处理的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-12-08

SpringBoot如何实现统一异常处理

这篇文章将为大家详细讲解有关SpringBoot如何实现统一异常处理,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1.介绍在日常开发中发生了异常,往往是需要通过一个统一的异常处理处理所有异常
2023-05-31

SpringBoot怎么进行统一异常处理

这篇文章主要介绍“SpringBoot怎么进行统一异常处理”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringBoot怎么进行统一异常处理”文章能帮助大家解决问题。1、处理前异常代码/**
2023-06-29

SpringBoot统一响应格式及统一异常处理

在我们开发SpringBoot后端服务时,一般需要给前端统一响应格式,本文主要介绍了SpringBoot统一响应格式及统一异常处理
2023-05-19

SpringBoot中怎么实现统一异常处理

在Spring Boot中,可以通过@ControllerAdvice注解来实现统一异常处理。以下是一个示例:@ControllerAdvicepublic class GlobalExceptionHandler {@Exceptio
SpringBoot中怎么实现统一异常处理
2024-03-07

SpringBoot中处理异常的方法是什么

在SpringBoot中处理异常的方法有以下几种:使用@ControllerAdvice注解和@ExceptionHandler注解来处理全局异常。通过创建一个全局异常处理类,使用@ControllerAdvice注解标记这个类,然后在方法
SpringBoot中处理异常的方法是什么
2024-03-07

springboot断言异常封装与统一异常处理实现代码

异常处理其实一直都是项目开发中的大头,但关注异常处理的人一直都特别少,下面这篇文章主要给大家介绍了关于springboot断言异常封装与统一异常处理的相关资料,需要的朋友可以参考下
2023-01-11

springboot全局异常处理的方法是什么

在Spring Boot中,可以使用`@ControllerAdvice`和`@ExceptionHandler`注解来实现全局异常处理。1. 创建一个全局异常处理类,使用`@ControllerAdvice`注解标记。该类可以捕获所有Co
2023-10-07

springboot处理异常的5种方式

本文主要介绍了springboot处理异常的5种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

使用Spring MVC实现统一异常处理的方法

这篇文章将为大家详细讲解有关使用Spring MVC实现统一异常处理的方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。1 描述 在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业
2023-05-31

Springboot项目异常处理及返回结果统一

这篇文章主要介绍了Springboot项目异常处理及返回结果统一,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录