1. Обзор
В прошлой статье мы рассмотрели основы Hystrix и то, как он может помочь в создании отказоустойчивого и отказоустойчивого приложения.
Существует множество существующих приложений Spring, которые делают вызовы к внешним системам, которые выиграют от Hystrix. К сожалению, может оказаться невозможным переписать эти приложения для интеграции Hystrix, однако возможен неинвазивный способ интеграции Hystrix с помощью Spring AOP .
В этой статье мы рассмотрим, как интегрировать Hystrix с существующим приложением Spring.
2. Hystrix в Spring-приложении
2.1. Существующее приложение
Давайте взглянем на существующий клиентский вызывающий объект приложения, который вызывает RemoteServiceTestSimulator
, созданный нами в предыдущей статье:
@Component("springClient")
public class SpringExistingClient {
@Value("${remoteservice.timeout}")
private int remoteServiceDelay;
public String invokeRemoteServiceWithOutHystrix() throws InterruptedException {
return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
}
}
Как видно из приведенного выше фрагмента кода, метод invokeRemoteServiceWithOutHystrix
отвечает за выполнение вызовов удаленной службы RemoteServiceTestSimulator .
Конечно, приложения реального мира не будут такими простыми.
2.2. Создать совет
Чтобы продемонстрировать, как интегрировать Hystrix, мы будем использовать этот клиент в качестве примера.
Для этого мы определим совет Around
, который сработает, когда будет выполнен invokeRemoteService
:
@Around("@annotation(com.foreach.hystrix.HystrixCircuitBreaker)")
public Object circuitBreakerAround(ProceedingJoinPoint aJoinPoint) {
return new RemoteServiceCommand(config, aJoinPoint).execute();
}
Вышеупомянутый совет разработан как совет Around
, который должен выполняться в pointcut, аннотированном @HystrixCircuitBreaker
.
Теперь посмотрим определение аннотации HystrixCircuitBreaker
:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HystrixCircuitBreaker {}
2.3. Логика Хайстрикс
Теперь давайте посмотрим на RemoteServiceCommand
. Он реализован как статический внутренний класс
в примере кода, чтобы инкапсулировать логику вызова Hystrix:
private static class RemoteServiceCommand extends HystrixCommand<String> {
private ProceedingJoinPoint joinPoint;
RemoteServiceCommand(Setter config, ProceedingJoinPoint joinPoint) {
super(config);
this.joinPoint = joinPoint;
}
@Override
protected String run() throws Exception {
try {
return (String) joinPoint.proceed();
} catch (Throwable th) {
throw new Exception(th);
}
}
}
Всю реализацию компонента Aspect
можно увидеть здесь .
2.4. Аннотировать с помощью @HystrixCircuitBreaker
Как только аспект определен, мы можем аннотировать наш клиентский метод с помощью @HystrixCircuitBreaker
, как показано ниже, и Hystrix будет вызываться при каждом вызове аннотированных методов:
@HystrixCircuitBreaker
public String invokeRemoteServiceWithHystrix() throws InterruptedException{
return new RemoteServiceTestSimulator(remoteServiceDelay).execute();
}
Приведенный ниже интеграционный тест продемонстрирует разницу между маршрутом Hystrix и маршрутом не Hystrix.
2.5. Протестируйте интеграцию
В целях демонстрации мы определили два маршрута выполнения метода: один с Hystrix, а другой без него.
public class SpringAndHystrixIntegrationTest {
@Autowired
private HystrixController hystrixController;
@Test(expected = HystrixRuntimeException.class)
public void givenTimeOutOf15000_whenClientCalledWithHystrix_thenExpectHystrixRuntimeException()
throws InterruptedException {
hystrixController.withHystrix();
}
@Test
public void givenTimeOutOf15000_whenClientCalledWithOutHystrix_thenExpectSuccess()
throws InterruptedException {
assertThat(hystrixController.withOutHystrix(), equalTo("Success"));
}
}
Когда тест выполняется, вы можете видеть, что вызов метода без Hystrix будет ожидать все время выполнения удаленной службы, тогда как маршрут Hystrix замкнется и вызовет HystrixRuntimeException
после определенного тайм-аута, который в нашем случае составляет 10 секунд.
3. Заключение
Мы можем создать один аспект для каждого вызова удаленной службы, который мы хотим сделать с различными конфигурациями. В следующей статье мы рассмотрим интеграцию Hystrix с самого начала проекта.
Весь код в этой статье можно найти в репозитории GitHub .