Java Spring - 多个配置文件处于活动状态

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38133808/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:01:41  来源:igfitidea点击:

Spring - Multiple Profiles active

javaspring

提问by Felipe S.

I basically have a bean in Spring that I wanted to activate only when 2 profiles are active. Basically, it would be like:

我基本上在 Spring 中有一个 bean,我只想在 2 个配置文件处于活动状态时激活它。基本上,它会是这样的:

@Profile({"Tomcat", "Linux"})
public class AppConfigMongodbLinux{...}

@Profile({"Tomcat", "WindowsLocal"})
public class AppConfigMongodbWindowsLocal{...}

So I'd like that when I use -Dspring.profiles.active=Tomcat,WindowsLocal, it would try to use only the AppConfigMongodbWindowsLocal, but it still tries to register the AppConfigMongodbLinux.

所以我希望当我使用 时-Dspring.profiles.active=Tomcat,WindowsLocal,它会尝试只使用AppConfigMongodbWindowsLocal,但它仍然尝试注册AppConfigMongodbLinux.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appConfigMongodbLinux': Injection of autowired dependencies failed

Is it possible to make the bean be registerd only when both profiles are active or am I using it incorrectly? :)

是否可以仅在两个配置文件都处于活动状态时才注册 bean,或者我是否错误地使用了它?:)

Thanks!!

谢谢!!



Edit: Posting the full stack.

编辑:发布完整堆栈。

The error is actually on a property that is missing on the properties, but will this bean get activated? I wanted to understand this to ensure I'm not activating a wrong bean..

错误实际上是在属性中缺少的属性上,但是这个 bean 会被激活吗?我想了解这一点以确保我没有激活错误的 bean..

org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
    ...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'appConfigMongodbLinux': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.Integer mycompany.config.AppConfigMongodbLinux.mongoPort; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'mongo.port' in string value "${mongo.port}"
    ... 40 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.Integer mycompany.config.AppConfigMongodbLinux.mongoPort; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'mongo.port' in string value "${mongo.port}"
    ...
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'mongo.port' in string value "${mongo.port}"

采纳答案by chrylis -cautiouslyoptimistic-

Unfortunately, @Profileactivates if anylisted profile is active. There are a couple of ways around this.

不幸的是,@Profile如果任何列出的配置文件处于活动状态,就会激活。有几种方法可以解决这个问题。

  • Apply the common @Profile("Tomcat")annotation to a top-level configuration class, and then apply @Profile("Windows")to a nested configuration class (or @Beanmethod).
  • If Spring Boot is acceptable as a dependency, use @AllNestedConditionsto create an annotation that's the AND instead of the OR.
  • 将公共@Profile("Tomcat")注解应用于顶级配置类,然后应用于@Profile("Windows")嵌套的配置类(或@Bean方法)。
  • 如果 Spring Boot 可以接受作为依赖项,请使用@AllNestedConditions创建一个注释,即 AND 而不是 OR。

It looks like what you're trying to do would be clean to write if you were using Spring Boot autoconfiguration classes; if it's practical to introduce autoconfiguration at this stage of your application's lifecycle, I recommend considering it.

如果您使用 Spring Boot 自动配置类,看起来您尝试做的事情写起来很干净;如果在应用程序生命周期的这个阶段引入自动配置是可行的,我建议考虑它。

回答by Miguel Pereira

@ConditionalOnExpression("#{environment.acceptsProfiles('Tomcat') && environment.acceptsProfiles('Linux')}")

Credits: Spring Source Code. Look up the @ConditionalOnExpression with your IDE then 'find usages' to see relevant examples within the source code. This will enable you to become a better developer.

致谢:Spring 源代码。使用您的 IDE 查找 @ConditionalOnExpression,然后“查找用法”以查看源代码中的相关示例。这将使您成为更好的开发人员。

回答by Laplas

Spring version 5.1and above offers additional functionality for specifying more complex profile string expressions. In your case desired functionality can be achieved in the following way:

Spring 5.1及更高版本提供了用于指定更复杂的配置文件字符串表达式的附加功能。在您的情况下,可以通过以下方式实现所需的功能:

@Profile({"Tomcat & Linux"})
@Configuration
public class AppConfigMongodbLinux {...}

Please read Using @Profilechapter from Spring reference documentation for more info.

请阅读Spring 参考文档中的Using @Profile章节以获取更多信息。

Update (method level profile expressions): Actually I've tested some @Bean method level profile expressions and everything works like a charm:

更新(方法级配置文件表达式):实际上我已经测试了一些 @Bean 方法级配置文件表达式,一切都像魅力一样:

/**
 * Shows basic usage of {@link Profile} annotations applied on method level.
 */
@Configuration
public class MethodLevelProfileConfiguration {

    /**
     * Point in time related to application startup.
     */
    @Profile("qa")
    @Bean
    public Instant startupInstant() {
        return Instant.now();
    }

    /**
     * Point in time related to scheduled shutdown of the application.
     */
    @Bean
    public Instant shutdownInstant() {
        return Instant.MAX;
    }

    /**
     * Point in time of 1970 year.
     */
    @Profile("develop & production")
    @Bean
    public Instant epochInstant() {
        return Instant.EPOCH;
    }
}

Integration tests:

集成测试:

/**
 * Verifies {@link Profile} annotation functionality applied on method-level.
 */
public class MethodLevelProfileConfigurationTest {

    @RunWith(SpringRunner.class)
    @ContextConfiguration(classes = MethodLevelProfileConfiguration.class)
    @ActiveProfiles(profiles = "qa")
    public static class QaActiveProfileTest {

        @Autowired
        private ApplicationContext context;

        @Test
        public void shouldRegisterStartupAndShutdownInstants() {
            context.getBean("startupInstant", Instant.class);
            context.getBean("shutdownInstant", Instant.class);

            try {
                context.getBean("epochInstant", Instant.class);
                fail();
            } catch (NoSuchBeanDefinitionException ex) {
                // Legal to ignore.
            }
        }
    }

    @RunWith(SpringRunner.class)
    @ContextConfiguration(classes = MethodLevelProfileConfiguration.class)
    @ActiveProfiles(profiles = {"develop", "production"})
    public static class MethodProfileExpressionTest {

        @Autowired
        private ApplicationContext context;

        @Test
        public void shouldRegisterShutdownAndEpochInstants() {
            context.getBean("epochInstant", Instant.class);
            context.getBean("shutdownInstant", Instant.class);

            try {
                context.getBean("startupInstant", Instant.class);
                fail();
            } catch (NoSuchBeanDefinitionException ex) {
                // Legal to ignore.
            }
        }
    }
}

Spring 5.1.2 version was tested.

Spring 5.1.2 版本已测试。