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

Fel*_* S. 17 java spring

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

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

@Profile({"Tomcat", "WindowsLocal"})
public class AppConfigMongodbWindowsLocal{...}
Run Code Online (Sandbox Code Playgroud)

所以当我使用时-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
Run Code Online (Sandbox Code Playgroud)

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

Tha*_*thu 17

仅当存在多个配置文件中的任何一个时才加载配置,请使用@Profile注释,如下所示:

@Profile({ "production", "preproduction" })
@Configuration
public class MyConfigClass {
    // code
}
Run Code Online (Sandbox Code Playgroud)

仅当所有多个配置文件都存在时才加载配置,请使用@Profile注释,如下所示:

@Profile({ "production & preproduction" })
@Configuration
public class MyConfigClass {
    // code
}
Run Code Online (Sandbox Code Playgroud)

要在存在任何某些配置文件时加载配置,请使用注释,如下所示:@Profile

@Profile({ "!production & !preproduction" })
@Configuration
public class MyConfigClass {
    // code
}
Run Code Online (Sandbox Code Playgroud)


chr*_*ke- 12

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

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

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

  • 或者来自`@ Profile`的条件实现,如https://gist.github.com/zapl/1262d21b8866ebc61e48ece505277f69 (2认同)

Mig*_*ira 6

@ConditionalOnExpression("#{environment.acceptsProfiles('Tomcat') && environment.acceptsProfiles('Linux')}")
Run Code Online (Sandbox Code Playgroud)

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


Lap*_*las 6

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

@Profile({"Tomcat & Linux"})
@Configuration
public class AppConfigMongodbLinux {...}
Run Code Online (Sandbox Code Playgroud)

请阅读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;
    }
}
Run Code Online (Sandbox Code Playgroud)

集成测试:

/**
 * 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.
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Spring 5.1.2版本已经过测试。