为了账号安全,请及时绑定邮箱和手机立即绑定

SpringMVC 断路器

标签:
Java

在分布式程序或者单机程序中,如果某一个接口的不可用,严重的将会引起整个应用的雪崩,跟现在家中的保险盒是一个道理,为了保护家中的电器都会加入保险丝,关于断路器的更多原理大家可以参考相关资料,此文只作简单介绍与使用。

使用说明

在项目中导入断路器的包,spring提供了一个,大家也可以自己写一个,比较复杂

gradle项目

compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-hystrix', version: '1.3.0.RELEASE'

maven项目

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.3.0.RELEASE</version>
</dependency>
核心配置

HystrixCommandAdvice.java

@Aspect
@Component
public class HystrixCommandAdvice {

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.GetMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.PostMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.PutMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
            " || @annotation(org.springframework.web.bind.annotation.PatchMapping)"
    )
    public void pointCut(){//aop拦截方法

    }

    @Around("pointCut()")
    public Object runCommand(final ProceedingJoinPoint pjp) {
        return wrapWithHystrixCommnad(pjp).execute();
    }

    private HystrixCommand<Object> wrapWithHystrixCommnad(final ProceedingJoinPoint pjp) {

        return new HystrixCommand<Object>(setter(pjp)) {
            @Override
            protected Object run() throws Exception {
                try {
                    return pjp.proceed();
                } catch (Throwable throwable) {
                    if(throwable instanceof ActException){//ActException是大家自定义的异常,断路器不会进行拦截,会把错误信息原封不对往外扔。
                        throw new HystrixBadRequestException(throwable.getMessage(),throwable);
                    }else{
                        throwable.printStackTrace();
                        throw (Exception) throwable;
                    }
                }
            }

            @Override
            protected Object getFallback() {//只要请求接口一错误,就会进到这个方法,可自行处理异常消息。
                return new ActResult("服务不可用");
            }
        };
    }

    private HystrixCommand.Setter setter(ProceedingJoinPoint joinPoint) {//此方法内包含对断路器的封装,如果大家不需要那么多也可以自行去掉大部分。
        Signature signature = joinPoint.getSignature();
        HystrixCommand.Setter setter = null;
        String groupName = signature.getDeclaringTypeName(),commandKey= "";
        int timeOut = 10000;//请求默认超时时间
        if(signature.getDeclaringType().isAnnotationPresent(DefaultProperties.class)){
            DefaultProperties defaultProperties = (DefaultProperties)signature.getDeclaringType().getDeclaredAnnotation(DefaultProperties.class);
            if(StringUtils.isNotBlank(defaultProperties.groupKey())){
                groupName = defaultProperties.groupKey();
            }
            defaultProperties.commandProperties();
            MethodSignature methodSignature = (MethodSignature) joinPoint
                    .getSignature();
            Method method = methodSignature.getMethod();
            com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand hystrixCommand  = method.getDeclaredAnnotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand.class);
            if(null!=hystrixCommand){
                if(StringUtils.isNotBlank(hystrixCommand.groupKey())){
                    groupName =  hystrixCommand.groupKey();
                }
                if(StringUtils.isNotBlank(hystrixCommand.commandKey())){
                    commandKey = groupName+"/"+hystrixCommand.commandKey();
                }
            }
            setter = HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("group/"+groupName)).andCommandKey(HystrixCommandKey.Factory.asKey("key/"+(StringUtils.isBlank(commandKey)?groupName:commandKey)));
            HystrixProperty[] hyps = defaultProperties.commandProperties();

            if(null!=hyps&&hyps.length>0){
                Optional<HystrixProperty> hystrixProperty = Arrays.asList(hyps).stream().filter(h->h.name().equals("execution.isolation.thread.timeoutInMilliseconds")).findFirst();
                if(hystrixProperty.isPresent()){
                    timeOut = Integer.parseInt(hystrixProperty.get().value());
                }
            }
            setter.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(timeOut));
        }else{
            setter = HystrixCommand.Setter
                    .withGroupKey(HystrixCommandGroupKey.Factory.asKey("group/default"))
                    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(timeOut))
                    .andCommandKey(HystrixCommandKey.Factory.asKey("key/"+(StringUtils.isBlank(commandKey)?groupName:commandKey)));
        }
        return setter;
    }

}

action可这么配置

@RestController
@RequestMapping("test")
@DefaultProperties
public class GroupAct {
    ....
}

或者

public class GroupAct {

    @HystrixCommand
    public Result add(){
        ...
    }
}

也可以结合使用,更多参数配置可参考spring官方写的文档。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消