spring 引导 @RestController 可以 enabled/disabled 使用属性吗?
Can a spring boot @RestController be enabled/disabled using properties?
给定 "standard" spring 引导应用程序 @RestController
,例如
@RestController
@RequestMapping(value = "foo", produces = "application/json;charset=UTF-8")
public class MyController {
@RequestMapping(value = "bar")
public ResponseEntity<String> bar(
return new ResponseEntity<>("Hello world", HttpStatus.OK);
}
}
是否存在阻止端点启动的注释或技术根本if/unless某个应用程序属性exists/doesn不存在.
注意:在方法内部测试属性并展开不是解决方案,因为端点将存在。
我不关心粒度:即 enabling/disabling 只是一个方法或整个 class 都可以。
因为配置文件不是 属性,通过配置文件控制不能解决我的问题。
我找到了一个使用 @ConditionalOnExpression
的简单解决方案:
@RestController
@ConditionalOnExpression("${my.controller.enabled:false}")
@RequestMapping(value = "foo", produces = "application/json;charset=UTF-8")
public class MyController {
@RequestMapping(value = "bar")
public ResponseEntity<String> bar(
return new ResponseEntity<>("Hello world", HttpStatus.OK);
}
}
加上这个注解,除非我有
my.controller.enabled=true
在我的 application.properties
文件中,控制器根本不会启动。
你也可以使用更方便的:
@ConditionalOnProperty("my.property")
其行为与上述完全相同;如果 属性 存在且 "true"
,组件启动,否则不启动。
添加到这个问题和另一个问题here.
这是我的回答:
我实际上会使用@RefreshScope Bean,然后当您想在运行时停止 Rest Controller 时,只需将所述控制器的 属性 更改为 false。
SO 的 引用了在运行时更改 属性。
这是我的工作代码片段:
@RefreshScope
@RestController
class MessageRestController(
@Value("${message.get.enabled}") val getEnabled: Boolean,
@Value("${message:Hello default}") val message: String
) {
@GetMapping("/message")
fun get(): String {
if (!getEnabled) {
throw NoHandlerFoundException("GET", "/message", null)
}
return message
}
}
还有其他使用过滤器的替代方法:
@Component
class EndpointsAvailabilityFilter @Autowired constructor(
private val env: Environment
): OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val requestURI = request.requestURI
val requestMethod = request.method
val property = "${requestURI.substring(1).replace("/", ".")}." +
"${requestMethod.toLowerCase()}.enabled"
val enabled = env.getProperty(property, "true")
if (!enabled.toBoolean()) {
throw NoHandlerFoundException(requestMethod, requestURI, ServletServerHttpRequest(request).headers)
}
filterChain.doFilter(request, response)
}
}
我假设这个问题来自于您在不同的环境中使用不同的 application.properties 文件这一事实。在这种情况下,您可以使用 spring 个配置文件并将配置分离到具有配置文件名称后缀的不同文件中,例如:
application.properties:
spring.profiles.active=@activatedProperties@
申请-local.properties:
//some config
申请-prod.properties:
//some config
然后在您的构建参数中,您可以通过添加选项来指定您要构建的环境:
-Dspring.profiles.active= //<-put here profile local or prod
然后在您的应用程序中,您可以通过添加
enable/disable 任何 spring bean
@Profile("put here profile name")
例如:
@RestController
@Profile("local")
@RequestMapping("/testApi")
public class RestForTesting{
//do some stuff
}
现在我的 RestForTesting 仅当我 运行 使用
创建的构建时才会创建
-Dspring.profiles.active=local
在某些情况下,@ConditionalOnXXX 无法工作,例如,依赖于另一个bean 实例来检查条件。 (XXXCondition class 无法调用 bean)。
在这种情况下,在 Java 配置文件中注册控制器。
查看源代码(Spring webmvc 5.1.6):
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.isHandler(Class<?>)
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
应该在控制器 bean 的类型级别添加 @RequestMapping 注释。参见:
@RequestMapping // Make Spring treat the bean as request handler
public class MyControllerA implements IMyController {
@RequestMapping(path = { "/path1" })
public .. restMethod1(...) {
........
}
}
@RequestMapping // Make Spring treat the bean as request handler
public class MyControllerB implements IMyController {
@RequestMapping(path = { "/path1" })
public .. restMethod1(...) {
........
}
}
@Configuration
public class ControllerConfiguration {
/**
*
* Programmatically register Controller based on certain condition.
*
*/
@Bean
public IMyController myController() {
IMyController controller;
if (conditionA) {
controller = new MyControllerA();
} else {
controller = new MyControllerB();
}
return controller;
}
}
给定 "standard" spring 引导应用程序 @RestController
,例如
@RestController
@RequestMapping(value = "foo", produces = "application/json;charset=UTF-8")
public class MyController {
@RequestMapping(value = "bar")
public ResponseEntity<String> bar(
return new ResponseEntity<>("Hello world", HttpStatus.OK);
}
}
是否存在阻止端点启动的注释或技术根本if/unless某个应用程序属性exists/doesn不存在.
注意:在方法内部测试属性并展开不是解决方案,因为端点将存在。
我不关心粒度:即 enabling/disabling 只是一个方法或整个 class 都可以。
因为配置文件不是 属性,通过配置文件控制不能解决我的问题。
我找到了一个使用 @ConditionalOnExpression
的简单解决方案:
@RestController
@ConditionalOnExpression("${my.controller.enabled:false}")
@RequestMapping(value = "foo", produces = "application/json;charset=UTF-8")
public class MyController {
@RequestMapping(value = "bar")
public ResponseEntity<String> bar(
return new ResponseEntity<>("Hello world", HttpStatus.OK);
}
}
加上这个注解,除非我有
my.controller.enabled=true
在我的 application.properties
文件中,控制器根本不会启动。
你也可以使用更方便的:
@ConditionalOnProperty("my.property")
其行为与上述完全相同;如果 属性 存在且 "true"
,组件启动,否则不启动。
添加到这个问题和另一个问题here.
这是我的回答:
我实际上会使用@RefreshScope Bean,然后当您想在运行时停止 Rest Controller 时,只需将所述控制器的 属性 更改为 false。
SO 的
这是我的工作代码片段:
@RefreshScope
@RestController
class MessageRestController(
@Value("${message.get.enabled}") val getEnabled: Boolean,
@Value("${message:Hello default}") val message: String
) {
@GetMapping("/message")
fun get(): String {
if (!getEnabled) {
throw NoHandlerFoundException("GET", "/message", null)
}
return message
}
}
还有其他使用过滤器的替代方法:
@Component
class EndpointsAvailabilityFilter @Autowired constructor(
private val env: Environment
): OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val requestURI = request.requestURI
val requestMethod = request.method
val property = "${requestURI.substring(1).replace("/", ".")}." +
"${requestMethod.toLowerCase()}.enabled"
val enabled = env.getProperty(property, "true")
if (!enabled.toBoolean()) {
throw NoHandlerFoundException(requestMethod, requestURI, ServletServerHttpRequest(request).headers)
}
filterChain.doFilter(request, response)
}
}
我假设这个问题来自于您在不同的环境中使用不同的 application.properties 文件这一事实。在这种情况下,您可以使用 spring 个配置文件并将配置分离到具有配置文件名称后缀的不同文件中,例如:
application.properties:
spring.profiles.active=@activatedProperties@
申请-local.properties:
//some config
申请-prod.properties:
//some config
然后在您的构建参数中,您可以通过添加选项来指定您要构建的环境:
-Dspring.profiles.active= //<-put here profile local or prod
然后在您的应用程序中,您可以通过添加
enable/disable 任何 spring bean@Profile("put here profile name")
例如:
@RestController
@Profile("local")
@RequestMapping("/testApi")
public class RestForTesting{
//do some stuff
}
现在我的 RestForTesting 仅当我 运行 使用
创建的构建时才会创建-Dspring.profiles.active=local
在某些情况下,@ConditionalOnXXX 无法工作,例如,依赖于另一个bean 实例来检查条件。 (XXXCondition class 无法调用 bean)。
在这种情况下,在 Java 配置文件中注册控制器。
查看源代码(Spring webmvc 5.1.6):
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.isHandler(Class<?>)
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
应该在控制器 bean 的类型级别添加 @RequestMapping 注释。参见:
@RequestMapping // Make Spring treat the bean as request handler
public class MyControllerA implements IMyController {
@RequestMapping(path = { "/path1" })
public .. restMethod1(...) {
........
}
}
@RequestMapping // Make Spring treat the bean as request handler
public class MyControllerB implements IMyController {
@RequestMapping(path = { "/path1" })
public .. restMethod1(...) {
........
}
}
@Configuration
public class ControllerConfiguration {
/**
*
* Programmatically register Controller based on certain condition.
*
*/
@Bean
public IMyController myController() {
IMyController controller;
if (conditionA) {
controller = new MyControllerA();
} else {
controller = new MyControllerB();
}
return controller;
}
}