如何使用 Resilience4j 断路器装饰外部依赖的服务方法(特别是在 spring 云配置服务器上)?

How to decorate service method in external dependency with Resilience4j circuit breaker (specifically on spring cloud config server)?

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

EnvironmentController class 是一个 Spring @RestController.

我在 CircuitBreaker 中看到用于装饰可调用对象、函数等的方法,但 none 似乎适用于此。 (我是 Resilience4j 的新手,所以我希望我缺少一个简单的解决方案。)

一种常见的方法(不仅针对 Resilience4j,而且通常针对 Spring)是使用 BeanPostProcessor(您可以看到一个不相关的示例 here).

然后在 beanPostProcessor 中,您可以获得 EnvironmentController 的句柄并使用 Resilience4j CicrcuitBreaking 逻辑环绕它的 implementation/method。

基本上,该方法类似于:

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

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

编辑:

一些代码(不确定它是否有效,还没有测试,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 profiles, String label) {
            return circuitBreaker.executeSupplier(() -> {
                log.info("such wow");
                return environmentController.labelled(name, profiles, label);
            });
        }
    }
}