使用 Spring boot 在运行时启用和禁用端点

arr*_*izo 4 spring spring-mvc spring-boot

假设我有以下控制器:

@RestController
public class MyController {
    @GetMapping("v1/remain")
    public MyObject getRemain() {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

如何使用 Spring boot 在运行时动态启用或禁用此端点?另外,是否可以在无需重新启动应用程序的情况下更改此设置?

Mal*_*hah 8

您可以使用 @ConditionalOnExpression 或 @ConditionalOnProperty

@RestController
@ConditionalOnExpression("${my.property:false}")
@RequestMapping(value = "my-end-point", produces = MediaType.APPLICATION_JSON_VALUE)
public class MyController {
    @RequestMapping(value = "endpoint1", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> endpoint1(
        return new ResponseEntity<>("Hello world", HttpStatus.OK);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在如果你想让上面的控制器工作,你需要在 application.properties 文件中添加以下内容。

my.controller.enabled=true
Run Code Online (Sandbox Code Playgroud)

没有上面的语句,它的行为就像上面的控制器不存在一样。

同样,

@ConditionalOnProperty("my.property")
Run Code Online (Sandbox Code Playgroud)

行为与上述完全相同;如果该属性存在且为“true”,则组件有效,否则无效。

  • 这是一种静态行为,而不是动态行为。 (2认同)

g00*_*00b 4

要在属性更改时动态重新加载 bean,您可以使用 Spring boot Actuator + Spring cloud,以便您可以访问端点/actuator/refresh

这可以通过添加以下依赖项来完成:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

后者确实需要您添加 Spring cloud 的 BOM,即:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
Run Code Online (Sandbox Code Playgroud)

现在您可以/actuator/refresh通过设置以下属性来启用端点:

 management.endpoints.web.exposure.include=refresh
Run Code Online (Sandbox Code Playgroud)

这将允许您发送一个POST调用/actuator/refresh,它将返回所有更改的属性的数组。


通过使用/actuator/refresh端点,它还允许您使用@RefreshScope注释来重新创建 bean。但是,有一些限制:

  1. @RefreshScope重新创建 bean,而不重新评估可能因刷新而更改的条件。这意味着该解决方案不适用于,如本问题的评论部分@RefreshScope所示。
  2. @RefreshScope也不能很好地与过滤器配合使用,如本期所示。

这意味着您有两个选择:

  1. 添加@RefreshScope到控制器中,自己做条件逻辑,例如:

    @RefreshScope
    @RestController
    @RequestMapping("/api/foo")
    public class FooController {
        @Value("${foo.controller.enabled}")
        private boolean enabled;
    
        @GetMapping
        public ResponseEntity<String> getFoo() {
            return enabled ? ResponseEntity.of("bar") : ResponseEntity.notFound().build();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这意味着您必须将此条件添加到控制器内的所有端点。我还没有验证您是否可以将其与方面一起使用。

  2. 另一个解决方案是一开始就不使用@RefreshScope,而是延迟获取要验证的属性。这允许您将其与过滤器一起使用,例如:

    public class FooFilter extends OncePerRequestFilter {
        private Environment environment;
    
        public FooFilter(Environment environment) {
            this.environment = environment;
        }
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            if ("true".equalsIgnoreCase(environment.getProperty("foo.controller.enabled"))) {
                filterChain.doFilter(request, response);
            } else {
                response.setStatus(HttpStatus.NOT_FOUND.value());
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    您还必须注册过滤器,例如使用:

    @Bean
    public FilterRegistrationBean<FooFilter> fooFilter(Environment environment) {
        FilterRegistrationBean<FooFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new FooFilter(environment));
        bean.addUrlPatterns("/api/foo");
        return bean;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,此方法仅从Environment. 刷新Environment本身仍然需要您使用端点/actuator/refresh