可以使用属性启用/禁用弹簧启动@RestController吗?

问题描述 投票:39回答:4

给出一个带有@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);
    }
}

是否存在注释或技术,如果/除非某个应用程序属性存在/不存在,则会阻止端点启动。

注意:测试方法内的属性并且爆炸不是解决方案,因为端点将存在。

我不关心粒度:即只启用/禁用方法或整个类都很好。


由于配置文件不是属性,因此通过配置文件进行控制并不能解决我的问题。

java spring spring-boot application-settings
4个回答
61
投票

我找到了一个使用@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
投票

在某些情况下,@ ConstditionalOnXXX无法工作,例如,依赖于另一个bean实例来检查条件。 (XXXCondition类不能调用bean)。

在这种情况下,请在Java配置文件中注册控制器。

参见源代码(Spring webmvc 5.1.6):

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.isHandler(类)

       @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;
    }
}

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
    }
}

还有其他使用Filter的替代方法:

@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)
    }
}

My Github explaining how to disable at runtime


-1
投票

我假设这个问题来自于您为不同的环境使用不同的application.properties文件。在这种情况下,您可以使用弹簧配置文件和单独的配置到配置文件名称后缀的不同文件中,例如:

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

© www.soinside.com 2019 - 2024. All rights reserved.