web-dev-qa-db-ja.com

プロパティを使用してスプリングブート@RestControllerを有効/無効にできますか?

「標準」スプリングブートアプリケーションに@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);
    }
}

特定のアプリケーションプロパティが存在する/存在しない場合を除いて、エンドポイントが開始するのを防ぐアノテーションまたはテクニックはありますか?.

注:エンドポイントが存在するため、メソッド内でプロパティをテストして爆発させることは解決策ではありません。

粒度については気にしません。つまり、メソッドまたはクラス全体のみを有効化/無効化しても問題ありません。


プロファイルはプロパティではないため、プロファイルを介した制御は私の問題を解決しません。

43
Bohemian

@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"の場合、コンポーネントは起動しますが、そうでない場合は起動しません。

68
Bohemian

場合によっては、@ 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;
    }
}
1
wangf

この質問と別の質問に追加 here。

これは私の答えです:

実際に@RefreshScope Beanを使用し、実行時にRESTコントローラーを停止する場合は、コントローラーのプロパティを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)
    }
}

実行時に無効にする方法を説明するGithub