- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SpringCloud feign服务熔断下的异常处理操作由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
今天做项目的时候,遇到一个问题,如果我调用某个服务的接口,但是这个服务挂了,同时业务要求这个接口的结果是必须的,那我该怎么办呢,答案是通过hystrix,但是又有一点,服务不是平白无故挂的(排除服务器停电等问题),也就是说有可能是timeout or wrong argument 等等,那么我该如何越过hystrix的同时又能将异常成功抛出呢 。
直接在controller中编写异常处理器方法 。
1
2
3
4
5
6
7
8
9
10
|
@RequestMapping
(
"/test"
)
public
ModelAndView test()
{
throw
new
TmallBaseException();
}
@ExceptionHandler
(TmallBaseException.
class
)
public
ModelAndView handleBaseException()
{
return
new
ModelAndView(
"error"
);
}
|
但是呢这种方法只能在这个controller中有效,如果其他的controller也抛出了这个异常,是不会执行的 。
1
2
3
4
5
6
7
8
9
10
|
@ControllerAdvice
public
class
AdminExceptionHandler
{
@ExceptionHandler
(TmallBaseException.
class
)
public
ModelAndView hAndView(Exception exception)
{
//logic
return
null
;
}
}
|
本质是aop代理,如名字所言,全局异常处理,可以处理任意方法抛出的异常 。
1
2
3
4
5
6
7
8
9
10
|
public
static
class
Tt
implements
HandlerExceptionResolver
{
@Override
public
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex)
{
//logic
return
null
;
}
}
|
然后在mvc配置中添加即可 。
1
2
3
4
5
6
7
8
|
@Configuration
public
class
MyConfiguration
extends
WebMvcConfigurerAdapter {
@Override
public
void
configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
//初始化异常处理器链
exceptionResolvers.add(
new
Tt());
}
}
|
接下来就是Fegin ,如果想自定义异常需要了解1个接口:ErrorDecoder 。
先来看下rmi调用结束后是如果进行decode的 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
Object executeAndDecode(RequestTemplate template)
throws
Throwable {
Request request = targetRequest(template);
//代码省略
try
{
if
(logLevel != Logger.Level.NONE) {
response =
logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
response.toBuilder().request(request).build();
}
if
(Response.
class
== metadata.returnType()) {
if
(response.body() ==
null
) {
return
response;
}
if
(response.body().length() ==
null
||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose =
false
;
return
response;
}
// Ensure the response body is disconnected
byte
[] bodyData = Util.toByteArray(response.body().asInputStream());
return
response.toBuilder().body(bodyData).build();
}
//从此处可以发现,如果状态码不再200-300,或是404的时候,意味着非正常响应就会对内部异常进行解析
if
(response.status() >=
200
&& response.status() <
300
) {
if
(
void
.
class
== metadata.returnType()) {
return
null
;
}
else
{
return
decode(response);
}
}
else
if
(decode404 && response.status() ==
404
&&
void
.
class
!= metadata.returnType()) {
return
decode(response);
}
else
{
throw
errorDecoder.decode(metadata.configKey(), response);
}
}
catch
(IOException e) {
if
(logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
}
throw
errorReading(request, response, e);
}
finally
{
if
(shouldClose) {
ensureClosed(response.body());
}
}
}
|
默认的解析方式是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
static
class
Default
implements
ErrorDecoder {
private
final
RetryAfterDecoder retryAfterDecoder =
new
RetryAfterDecoder();
@Override
public
Exception decode(String methodKey, Response response) {
//获取错误状态码,生成fegin自定义的exception
FeignException exception = errorStatus(methodKey, response);
Date retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers(), RETRY_AFTER));
if
(retryAfter !=
null
) {
//如果重试多次失败,则抛出相应的exception
return
new
RetryableException(exception.getMessage(), exception, retryAfter);
}
//否则抛出默认的exception
return
exception;
}
|
我们可以发现,做了2件事,第一获取状态码,第二重新抛出异常,额外的判断是否存在多次失败依然error的异常,并没有封装太多的异常,既然如此那我们就可以封装我们自定义的异常了 。
但是注意,这块并没有涉及hystrix,也就意味着对异常进行处理还是会触发熔断机制,具体避免方法最后讲 。
首先我们编写一个BaseException 用于扩展:省略getter/setter 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
public
class
TmallBaseException
extends
RuntimeException
{
/**
*
* @author joker
* @date 创建时间:2018年8月18日 下午4:46:54
*/
private
static
final
long
serialVersionUID = -5076254306303975358L;
// 未认证
public
static
final
int
UNAUTHENTICATED_EXCEPTION =
0
;
// 未授权
public
static
final
int
FORBIDDEN_EXCEPTION =
1
;
// 超时
public
static
final
int
TIMEOUT_EXCEPTION =
2
;
// 业务逻辑异常
public
static
final
int
BIZ_EXCEPTION =
3
;
// 未知异常->系统异常
public
static
final
int
UNKNOWN_EXCEPTION =
4
;
// 异常码
private
int
code;
// 异常信息
private
String message;
public
TmallBaseException(
int
code, String message)
{
super
(message);
this
.code = code;
this
.message = message;
}
public
TmallBaseException(String message, Throwable cause)
{
super
(message, cause);
this
.message = message;
}
public
TmallBaseException(
int
code, String message, Throwable cause)
{
super
(message, cause);
this
.code = code;
this
.message = message;
}
}
|
OK,我们定义好了基类之后可以先进行测试一番:服务接口controller:
1
2
3
4
5
6
7
|
//显示某个商家合作的店铺
@RequestMapping
(value=
"/store"
)
public
ResultDTO<Collection<BrandDTO>>findStoreOperatedBrands(
@RequestParam
(
"storeId"
)Long storeId)
{
为了测试,先直接抛出异常
throw
new
TmallBaseException(TmallBaseException.BIZ_EXCEPTION,
"ceshi"
);
}
|
接口:
1
2
|
@RequestMapping
(value=
"/auth/brand/store"
,method=RequestMethod.POST,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
ResultDTO<List<BrandDTO>>findStoreOperatedBrands(
@RequestParam
(
"storeId"
)Long storeId);
|
其余的先不贴了,然后我们发起rest调用的时候发现,抛出异常之后并没有被异常处理器处理,这是因为我们是通过fegin,而我又配置了feign的fallback类,抛出异常的时候会自动调用这个类中的方法. 。
1.直接撤除hystrix ,很明显its not a good idea 。
2.再封装一层异常类,具体为何,如下 。
AbstractCommand#handleFallback 函数是处理异常的函数,从方法后缀名可以得知,当exception 是HystrixBadRequestException的时候是直接抛出的,不会触发fallback,也就意味着不会触发降级 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
final
Func1<Throwable, Observable<R>> handleFallback =
new
Func1<Throwable, Observable<R>>() {
@Override
public
Observable<R> call(Throwable t) {
circuitBreaker.markNonSuccess();
Exception e = getExceptionFromThrowable(t);
executionResult = executionResult.setExecutionException(e);
if
(e
instanceof
RejectedExecutionException) {
return
handleThreadPoolRejectionViaFallback(e);
}
else
if
(t
instanceof
HystrixTimeoutException) {
return
handleTimeoutViaFallback();
}
else
if
(t
instanceof
HystrixBadRequestException) {
return
handleBadRequestByEmittingError(e);
}
else
{
/*
* Treat HystrixBadRequestException from ExecutionHook like a plain HystrixBadRequestException.
*/
if
(e
instanceof
HystrixBadRequestException) {
eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);
return
Observable.error(e);
}
return
handleFailureViaFallback(e);
}
}
};
|
既然如此,那一切都明了了,修改类的继承结构即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public
class
TmallBaseException
extends
HystrixBadRequestException
{
/**
*
* @author joker
* @date 创建时间:2018年8月18日 下午4:46:54
*/
private
static
final
long
serialVersionUID = -5076254306303975358L;
// 未认证
public
static
final
int
UNAUTHENTICATED_EXCEPTION =
0
;
// 未授权
public
static
final
int
FORBIDDEN_EXCEPTION =
1
;
// 超时
public
static
final
int
TIMEOUT_EXCEPTION =
2
;
// 业务逻辑异常
public
static
final
int
BIZ_EXCEPTION =
3
;
// 未知异常->系统异常
public
static
final
int
UNKNOWN_EXCEPTION =
4
;
// 异常码
private
int
code;
// 异常信息
private
String message;
}
|
至于怎么从服务器中获取异常然后进行转换,就是通过上面所讲的ErrorHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public
class
TmallErrorDecoder
implements
ErrorDecoder
{
@Override
public
Exception decode(String methodKey, Response response)
{
System.out.println(methodKey);
Exception exception=
null
;
try
{
String json = Util.toString(response.body().asReader());
exception=JsonUtils.json2Object(json,TmallBaseException.
class
);
}
catch
(IOException e)
{
e.printStackTrace();
}
return
exception!=
null
?exception:
new
TmallBaseException(TmallBaseException.UNKNOWN_EXCEPTION,
"系统运行异常"
);
}
}
|
最后微服务下的全局异常处理就ok了,当然这个ErrorDdecoder 和BaseException推荐放在common模块下,所有其它模块都会使用到它.
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我.
原文链接:https://blog.csdn.net/Coder_Joker/article/details/81811567 。
最后此篇关于SpringCloud feign服务熔断下的异常处理操作的文章就讲到这里了,如果你想了解更多关于SpringCloud feign服务熔断下的异常处理操作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
问题很简单:我正在寻找一种优雅的使用方式 CompletableFuture#exceptionally与 CompletableFuture#supplyAsync 一起.这是行不通的: priva
对于 Web 服务,我们通常使用 maven-jaxb2-plugin 生成 java bean,并在 Spring 中使用 JAXB2 编码。我想知道如何处理 WSDL/XSD 中声明的(SOAP-
这个问题已经有答案了: Array index out of bound behavior (10 个回答) 已关闭 8 年前。 我对下面的 C 代码感到好奇 int main(){
当在类的开头使用上下文和资源初始化 MediaPlayer 对象时,它会抛出 NullPointer 异常,但是当在类的开头声明它时(因此它是 null),然后以相同的方式初始化它在onCreate方
嘿 我尝试将 java 程序连接到 REST API。 使用相同的代码部分,我在 Java 6 中遇到了 Java 异常,并且在 Java 8 中运行良好。 环境相同: 信任 机器 unix 用户 代
我正在尝试使用 Flume 和 Hive 进行 Twitter 分析。为了从 twitter 获取推文,我在 flume.conf 文件中设置了所有必需的参数(consumerKey、consumer
我在 JavaFX 异常方面遇到一些问题。我的项目在我的 Eclipse 中运行,但现在我的 friend 也尝试访问该项目。我们已共享并直接保存到保管箱文件夹中。但他根本无法让它发挥作用。他在控制台
假设我使用 blur() 事件验证了电子邮件 ID,我正在这样做: $('#email').blur(function(){ //make ajax call , check if dupli
我这样做是为了从 C 代码调用非托管函数。 pCallback 是一个函数指针,因此在托管端是一个委托(delegate)。 [DllImport("MyDLL.dll")] public stati
为什么这段代码是正确的: try { } catch(ArrayOutOfBoundsException e) {} 这是错误的: try { } catch(IOException e) {} 这段
我遇到了以下问题:有导出函数的DLL。 代码示例如下:[动态链接库] __declspec(dllexport) int openDevice(int,void**) [应用] 开发者.h: __de
从其他线程,我知道我们不应该在析构函数中抛出异常!但是对于下面的例子,它确实有效。这是否意味着我们只能在一个实例的析构函数中抛出异常?我们应该如何理解这个代码示例! #include using n
为什么需要异常 引出 public static void main(String[
1. Java的异常机制 Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别。JDK中内
我是 Python 的新手,我对某种异常方法的实现有疑问。这是代码(缩写): class OurException(Exception): """User defined Exception"
我已经创建了以下模式来表示用户和一组线程之间的关联,这些线程按他们的最后一条消息排序(用户已经阅读了哪些线程,哪些没有): CREATE TABLE table(user_id bigint, mes
我正在使用 Python 编写一个简单的自动化脚本,它可能会在多个位置引发异常。在他们每个人中,我都想记录一条特定的消息并退出程序。为此,我在捕获异常并处理它(执行特定的日志记录操作等)后引发 Sys
谁能解释一下为什么这会导致错误: let xs = [| "Mary"; "Mungo"; "Midge" |] Array.iter printfn xs 虽然不是这样: Array.iter pr
在我使用 Play! 的网站上,我有一个管理部分。所有 Admin Controller 都有一个 @With 和一个 @Check 注释。 断开连接后,一切正常。连接后,每次加载页面(任何页面,无论
我尝试连接到 azure 表存储并添加一个对象。它在本地主机上工作得很好,但是在我使用的服务器上我得到以下异常及其内部异常: Exception of type 'Microsoft.Wind
我是一名优秀的程序员,十分优秀!