如何使用 Resilience4j 断路器装饰外部依赖中的服务方法特别是在 Spring Cloud 配置服务器上?

问题描述

如何使用 Resilience4j 断路器装饰外部库中的服务方法?具体来说,我想在 spring 云配置服务器(服务器本身,而不是客户端代码)中装饰一个方法org.springframework.cloud.config.server.environment.EnvironmentController.labelled(...)。它需要多个参数。我无法对其进行注释,因为它位于第 3 方库中。

EnvironmentController 类是 Spring @RestController

我在 CircuitBreaker 中看到了用于装饰 Callables、Functions 等的方法,但似乎没有一个方法适用于此。 (我对 Resilience4j 完全陌生,所以我希望我错过了一个简单的解决方案。)

解决方法

一种常见的方法(不仅是 Resilience4j,而且是一般的 Spring)是使用 BeanPostProcessor(你可以看到一个不相关的例子 here ).

然后在 beanPostProcessor 中,您可以获得 EnvironmentController 的句柄,并使用 Resilience4j CicrcuitBreaking 逻辑环绕其实现/方法。

基本上该方法类似于:

  • 在您的 BeanPostProcessor 中使用 @Configuration 来处理完全连接的 EnvironmentController
  • 使用 Resilience4j 围绕您感兴趣的 CircuitBreaker 方法包装您自己的 EnvirommentController 实现
  • 利润

如果这不能完全清除图片,我可以添加一些示例代码来帮助您入门,请告诉我。请记住,这可能只是解决此问题的众多方法之一。

编辑:

一些代码(不确定它是否有效,还没有测试,spring-boot 在为 MVC 映射自动配置使用大量 aop 方面是出了名的烦人,所以你可能不得不使用方面或代理配置代替),可能看起来像(请记住,为了后代,我会使用 lombok 来避免所有样板文件):

@Configuration
@Slf4j
public class MyConfig {

    // or however the heck you get your breaker config
    private final CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom().build();
    private final CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);
    private final CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("suchBreakerMuchWow");

    @Bean
    public CircuitBreakerAwarePostProcessor circuitBreakerAwarePostProcessor() {
        return new CircuitBreakerAwarePostProcessor();
    }

    public class CircuitBreakerAwarePostProcessor implements BeanPostProcessor {

        @Override
        public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException {
            if (bean instanceof EnvironmentController) {
                return new CircuitBreakerFriendlyEnvironmentController((EnvironmentController) bean);
            }
            return bean;
        }
    }

    private interface Exclude {
        Environment labelled (String name,String profiles,String label);
    }

    @RequiredArgsConstructor
    private class CircuitBreakerFriendlyEnvironmentController implements Exclude {

        @Delegate(types = EnvironmentController.class,excludes = Exclude.class)
        @NonNull private final EnvironmentController environmentController;

        @Override
        public Environment labelled(String name,String label) {
            return circuitBreaker.executeSupplier(() -> {
                log.info("such wow");
                return environmentController.labelled(name,profiles,label);
            });
        }
    }
}