给出带有@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);
}
}
是否有注释或技术阻止端点 at all 如果/除非某个应用程序属性存在/不存在。
注意:测试方法内的属性并且爆炸不是解决方案,因为端点将存在。
我不关心粒度:即启用/禁用方法或整个类都很好。
由于个人资料不是属性,因此通过个人资料进行控制无法解决我的问题。
答案 0 :(得分:59)
我找到了一个使用@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"
,则组件启动,否则不启动。
答案 1 :(得分:0)
在这个问题和另一个问题here.
中添加这是我的答案:
我实际上会使用@RefreshScope Bean,然后当您想在运行时停止Rest Controller时,只需要将该控制器的属性更改为false。
SO的link引用运行时更改的属性。
以下是我的工作代码段:
@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)
}
}
答案 2 :(得分:0)
在某些情况下,@ ConditionalOnXXX无法工作,例如,依赖于另一个bean实例来检查条件。 (XXXCondition类无法调用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 hanlder
public class MyControllerA {
@RequestMapping(path = { "/path1" })
public .. restMethod1(...) {
........
}
}
@RequestMapping // Make Spring treat the bean as request hanlder
public class MyControllerB {
@RequestMapping(path = { "/path1" })
public .. restMethod1(...) {
........
}
}
@Configuration
public class ControllerConfiguration {
/**
*
* Programmingly register Controller based on certain condition.
*
*/
@Bean
public IMyController myController() {
IMyController controller;
if (conditionA) {
cntroller = new MyControllerA();
} else {
controller = new MyControllerB();
}
return controller;
}
}
答案 3 :(得分:-1)
我认为此问题来自以下事实:您针对不同的环境使用了不同的application.properties文件。在这种情况下,您可以使用spring配置文件并将配置单独配置到带有配置文件名称后缀的不同文件中,例如:
application.properties:
spring.profiles.active=@activatedProperties@
application-local.properties:
//some config
application-prod.properties:
//some config
然后在构建参数中,您可以通过添加选项来指定要构建的环境:
-Dspring.profiles.active= //<-put here profile local or prod
然后在您的应用程序中,您可以通过添加
启用/禁用任何spring bean。@Profile("put here profile name")
例如:
@RestController
@Profile("local")
@RequestMapping("/testApi")
public class RestForTesting{
//do some stuff
}
现在,仅当我运行使用
创建的版本时,我的RestForTesting才会创建 -Dspring.profiles.active=local