Can a spring boot @RestController be enabled/disabled using properties?

后端 未结 4 870
别那么骄傲
别那么骄傲 2020-12-01 01:42

Given a \"standard\" spring boot application with a @RestController, eg

@RestController
@RequestMapping(value = \"foo\", produces = \"applicatio         


        
相关标签:
4条回答
  • 2020-12-01 02:20

    I assume this question comes from the fact that you are using different application.properties files for your different enviroments. In this case you can use spring profiles and separate configurations into different files with profile name suffix for example:

    application.properties:

    spring.profiles.active=@activatedProperties@
    

    application-local.properties:

     //some config
    

    application-prod.properties:

    //some config
    

    then in your build paramethers you can specify which enviroment are you building by adding option:

    -Dspring.profiles.active= //<-put here profile local or prod
    

    then in your application you can enable/disable any spring bean by adding

    @Profile("put here profile name")
    

    for example:

    @RestController
    @Profile("local")
    @RequestMapping("/testApi")
    public class RestForTesting{
    
    //do some stuff
    
    }
    

    now my RestForTesting will be created only if im running a build created with

    -Dspring.profiles.active=local

    0 讨论(0)
  • 2020-12-01 02:22

    Adding to this question and another question here.

    This is my answer:

    I would actually used the @RefreshScope Bean and then when you want to stop the Rest Controller at runtime, you only need to change the property of said controller to false.

    SO's link referencing to changing property at runtime.

    Here are my snippets of working code:

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

    And there are other alternatives of using 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

    0 讨论(0)
  • 2020-12-01 02:23

    In some case, the @ConditionalOnXXX cannot work, for example, depends on another bean instance to check condition. (XXXCondition class cannot invoke a bean).

    In such case, register controller in Java configuration file.

    See source code(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));
           }
    

    Should add @RequestMapping annotation on type level for the controller bean. See:

    @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 讨论(0)
  • 2020-12-01 02:36

    I found a simple solution using @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);
        }
    }
    

    With this annotation added, unless I have

    my.controller.enabled=true
    

    in my application.properties file, the controller won't start at all.

    You can also use the more convenient:

    @ConditionalOnProperty("my.property")
    

    Which behaves exactly as above; if the property is present and "true", the component starts, otherwise it doesn't.

    0 讨论(0)
提交回复
热议问题