- 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的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
高可用的三大利器是熔断、限流和降级。它们都是在分布式系统中用于保障系统稳定性和可用性的重要策略。 熔断(Circuit Breaker):熔断是一种防止故障扩散的机制。当一个服务出现故障或超时
近年来,各大厂Google、微软、阿里、腾讯等都在提高可用的概念。高可用(High Availability,简称HA)是指系统或服务在遭受故障或异常情况时仍能持续提供稳定和可靠的运行能力。
我是一名优秀的程序员,十分优秀!