SpringMVC 断路器

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

使用说明

在项目中导入断路器的包,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官方写的文档。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,554评论 19 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 47,273评论 6 342
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 179,034评论 25 709
  • 妈的,又要开始了。每每听到同办公室妇人叨叨的话语,我的内心总是有千万草泥马在狂奔。 1 昨晚我们同室的新疆情侣又在...
    冬天寻兔子阅读 471评论 0 1
  • 還是覺得在文字的世界里,可以自由的遨遊,我喜歡文字,卻發現自己最近總是逃避問題,虛度光陰和年華,我的內心感到了...
    Elegant倩阅读 328评论 0 0

友情链接更多精彩内容