簡體   English   中英

Spring - 多個配置文件處於活動狀態

[英]Spring - Multiple Profiles active

我基本上在 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}"

Spring 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 版本已測試。

不幸的是, @Profile激活如有上市配置被激活。 有幾種方法可以解決這個問題。

  • 將常見的@Profile("Tomcat")注釋應用於頂級配置類,然后將@Profile("Windows")應用於嵌套的配置類(或@Bean方法)。
  • 如果 Spring Boot 可接受作為依賴項,請使用@AllNestedConditions創建一個注釋,即 AND 而不是 OR。

如果您使用 Spring Boot 自動配置類,看起來您嘗試做的事情寫起來很干凈; 如果在應用程序生命周期的這個階段引入自動配置是可行的,我建議考慮它。

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

致謝:Spring 源代碼。 使用您的 IDE 查找 @ConditionalOnExpression,然后“查找用法”以查看源代碼中的相關示例。 這將使您成為更好的開發人員。

第一個配置文件位於頂級。 第二個我是這樣檢查的:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM