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

时间:2016-06-30 21:48:34

标签: java spring

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

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

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

因此,当我使用-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

是否可以仅在两个配置文件都处于活动状态时才注册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}"

4 个答案:

答案 0 :(得分:10)

不幸的是,如果任何列出的个人资料处于有效状态,@Profile会激活。有很多方法可以解决这个问题。

  • 将公共@Profile("Tomcat")注释应用于顶级配置类,然后将@Profile("Windows")应用于嵌套配置类(或@Bean方法)。
  • 如果Spring Boot可以作为依赖项使用,请使用@AllNestedConditions创建一个AND而不是OR的注释。

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

答案 1 :(得分:3)

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

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

有关详细信息,请阅读Spring参考文档中的Using @Profile一章。

更新(方法级别配置文件表达式): 实际上,我已经测试了一些@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;
    }
}

集成测试:

/**
 * 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版本已经过测试。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

第一个配置文件位于顶层。 我这样检查的第二个:

@Autowired
private Environment env;
...
final boolean isMyProfile = Arrays.stream(env.getActiveProfiles()).anyMatch("MyProfile"::equals);