#232 基于Hystrix的系统保护,Day2. 演示

This commit is contained in:
Calvin
2013-07-04 18:09:19 +08:00
parent 1d85ed284c
commit ef4e6bc5e4
7 changed files with 100 additions and 7 deletions
@@ -2,7 +2,9 @@ package org.springside.examples.quickstart.rest;
import javax.validation.ConstraintViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -15,7 +17,9 @@ public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { ConstraintViolationException.class })
public final ResponseEntity<?> handleException(ConstraintViolationException ex, WebRequest request) {
return new ResponseEntity(BeanValidators.extractPropertyAndMessage(ex.getConstraintViolations()),
HttpStatus.BAD_REQUEST);
String body = BeanValidators.extractPropertyAndMessage(ex.getConstraintViolations()).toString();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return handleExceptionInternal(ex, body, null, HttpStatus.BAD_REQUEST, request);
}
}
@@ -1,5 +1,6 @@
package org.springside.examples.showcase.demos.hystrix.resource;
import org.hibernate.service.spi.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
@@ -18,7 +19,7 @@ import org.springside.modules.utils.Threads;
*/
@Controller
public class ResourceController {
public static final int TIMEOUT = 20000;
public static final int TIMEOUT = 10000;
@Autowired
private AccountEffectiveService accountService;
@@ -39,7 +40,7 @@ public class ResourceController {
}
if ("fail".equals(HystrixController.status)) {
throw new RuntimeException("Server Exception");
throw new ServiceException("Server Exception");
}
return null;
@@ -5,6 +5,8 @@ import org.springside.examples.showcase.webservice.rest.UserDTO;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
public class GetUserCommand extends HystrixCommand<UserDTO> {
@@ -13,7 +15,20 @@ public class GetUserCommand extends HystrixCommand<UserDTO> {
private RestTemplate restTemplate = new RestTemplate();
protected GetUserCommand(Long id) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("GetUserCommand"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
// 线程超时,默认为1秒,设为3秒,
.withExecutionIsolationThreadTimeoutInMilliseconds(3000)
// 至少多少请求在rolling window内发生,开始触发短路的计算,默认为20, 设为3
.withCircuitBreakerRequestVolumeThreshold(3)
// 多少百分比的fail在rolling windows内发生,计算为短路。默认为50%
.withCircuitBreakerErrorThresholdPercentage(50)
// 被置成短路后,多久才会重新尝试访问资源。默认为5秒,设为10秒
.withCircuitBreakerSleepWindowInMilliseconds(10000)
// rolling windows 长度,默认为10秒,设为20秒。
.withMetricsRollingStatisticalWindowInMilliseconds(20000)));
this.id = id;
}
@@ -1,10 +1,14 @@
package org.springside.examples.showcase.demos.hystrix.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springside.examples.showcase.webservice.rest.RestException;
import org.springside.examples.showcase.webservice.rest.UserDTO;
/**
@@ -12,10 +16,18 @@ import org.springside.examples.showcase.webservice.rest.UserDTO;
*/
@Controller
public class ServiceController {
private static Logger logger = LoggerFactory.getLogger(ServiceController.class);
@RequestMapping(value = "/hystrix/service/{id}", method = RequestMethod.GET)
@ResponseBody
public UserDTO getUser(@PathVariable("id") Long id) {
GetUserCommand command = new GetUserCommand(id);
return command.execute();
try {
return command.execute();
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RestException(HttpStatus.SERVICE_UNAVAILABLE);
}
}
}
@@ -0,0 +1,20 @@
package org.springside.examples.showcase.webservice.rest;
import org.springframework.http.HttpStatus;
public class RestException extends RuntimeException {
public HttpStatus status;
public RestException() {
}
public RestException(HttpStatus status) {
this.status = status;
}
public RestException(HttpStatus status, String message) {
super(message);
this.status = status;
}
}
@@ -0,0 +1,37 @@
package org.springside.examples.showcase.webservice.rest;
import javax.validation.ConstraintViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springside.modules.beanvalidator.BeanValidators;
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { ConstraintViolationException.class })
public final ResponseEntity<?> handleException(ConstraintViolationException ex, WebRequest request) {
String body = BeanValidators.extractPropertyAndMessage(ex.getConstraintViolations()).toString();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return handleExceptionInternal(ex, body, headers, HttpStatus.BAD_REQUEST, request);
}
@ExceptionHandler(value = { RestException.class })
public final ResponseEntity<?> handleException(RestException ex, WebRequest request) {
String body = ex.getMessage();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
HttpStatus status = (ex.status != null) ? ex.status : HttpStatus.INTERNAL_SERVER_ERROR;
return handleExceptionInternal(ex, body, headers, status, request);
}
}
@@ -15,6 +15,8 @@
<body>
<h1>Hystrix 演示</h1>
<p><a href="https://github.com/Netflix/Hystrix" target="_blank">Netflix Hystrix</a> 是一个延迟与容错类库,通过独立访问远程系统、服务和第三方库的节点,在复杂的分布式系统里停止雪崩及提供恢复能力。</p>
<h2>当前资源状态为<%= HystrixController.status %></h2>
<ul>
@@ -22,6 +24,8 @@
<li><a href="${ctx}/story/hystrix/fail">切换为Fail</a></li>
<li><a href="${ctx}/story/hystrix/normal">切换为Normal</a></li>
</ul>
<h2>访问Hystrix服务</h2>
<a href="${ctx}/hystrix/service/1" target="_blank"> ${ctx}/hystrix/service/1</a>
</body>
</html>