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