【发布时间】:2020-10-02 22:34:04
【问题描述】:
是否可以在Java配置中定义一个Spring RestController(@RestController注解类)单独(@Configuration方法中注解@Bean的类)? p>
我有一个由 spring boot 管理的应用程序(版本无关紧要,即使是最后一个可用的版本)。此应用程序使用 REST 公开了一些端点,因此有几个 REST 控制器,它们依次调用服务(像往常一样)。
现在取决于配置(application.yml 中的属性),我想避免启动一些服务,比如用 @RestController 注释注释的 2 个类,因为它们处理我想要排除的“功能 X”。
我想通过 Java 配置 配置我所有的 bean,这是一个要求。所以我最初的方法是在一个单独的配置中定义所有 bean(控制器和服务),该配置由 spring boot 在扫描期间找到)并在配置上放置一个@ConditionalOnProperty,以便它出现在一个地方:
@Configuration
public class MyAppGeneralConfiguration {
// here I define all the beans that are not relevant for "feature X"
@Bean
public ServiceA serviceA() {}
...
}
@Configuration
@ConditionalOnProperty(name = "myapp.featureX.enabled", havingValue = "true")
public class MyAppFeatureXConfiguration {
// here I will define all the beans relevant for feature X:
@Bean
public ServiceForFeatureX1 serviceForFeatureX1() {}
@Bean
public ServiceForFeatureX2 serviceForFeatureX2() {}
}
使用这种方法,我的服务根本没有任何 spring 注释,并且我不使用 @Autowired 注释,因为所有内容都是通过 @Configuration 类中的构造函数注入的:
// no @Service / @Component annotation
public class ServiceForFeatureX1 {}
现在我的问题是关于带有@RestContoller 注释的类。假设我有 2 个这样的控制器:
@RestController
public class FeatureXRestController1 {
...
}
@RestController
public class FeatureXRestController2 {
...
}
理想情况下,我也想在 Java 配置中定义它们,这样当我禁用该功能时,这两个控制器甚至都不会加载:
@ConditionalOnProperty(name = "myapp.featureX.enabled", havingValue = "true", matchIfMissing=true)
public class MyAppFeatureXConfiguration {
@Bean
@RestController // this doesn't work because the @RestController has target Type and can't be applied
// to methods
public FeatureXRestController1 featureXRestController1() {
}
所以问题基本上是可以做到吗?
RestController 是一个控制器,它又是一个组件,因此它受到组件扫描的影响。因此,如果功能 X 被禁用,功能 X 的其余控制器仍将开始加载并失败 因为不会有“服务”——配置中排除了bean,所以spring boot将无法注入。
我想到的一种方法是定义一个特殊的注释,如 @FeatureXRestController 并将其设为 @RestController 并将 @ConditionalOnProperty 放在那里,但它仍然是两个地方,这是我能想到的最佳解决方案:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RestController
@ConditionalOnProperty(name = "myapp.featureX.enabled", havingValue = "true", matchIfMissing=true)
public @interface FeatureXRestController {
}
...
@FeatureXRestController
public class FeatureXRestController1 {...}
@FeatureXRestController
public class FeatureXRestController2 {...}
【问题讨论】:
-
所以您只想启动应用程序的一部分?你读过@Profile 吗?这样,您可以通过可以设置为 env var 的属性来区分应用程序的哪些部分
-
是的,完全正确 - 这样该部分将包括休息控制器以及其他 bean
-
使用@Profile,如果您将其命名为 application-yourProfile.yml,您还可以为每个配置创建 Application.properties
-
当您使用 Spring boot 时,您也可以使用条件 bean 属性 docs.spring.io/spring-boot/docs/current/api/org/springframework/… .
-
好吧,我使用条件,它是 profile 的概括(因为 spring 4 @profile 是作为条件实现的)所以我在问题末尾提供的解决方案确实使用了这种技术。我在问是否有更好的解决方案可以提出。
标签: java spring spring-boot spring-mvc