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 在运行时动态启用或禁用此端点?另外,是否可以在无需重新启动应用程序的情况下更改此设置?
您可以使用 @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”,则组件有效,否则无效。
要在属性更改时动态重新加载 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。但是,有一些限制:
@RefreshScope重新创建 bean,而不重新评估可能因刷新而更改的条件。这意味着该解决方案不适用于,如本问题的评论部分@RefreshScope所示。@RefreshScope也不能很好地与过滤器配合使用,如本期所示。这意味着您有两个选择:
添加@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)
这意味着您必须将此条件添加到控制器内的所有端点。我还没有验证您是否可以将其与方面一起使用。
另一个解决方案是一开始就不使用@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。
| 归档时间: |
|
| 查看次数: |
6669 次 |
| 最近记录: |