Переопределение Spring @PropertySource by @Import

У меня есть свойство test=default в классе DefaultConfig, и я делаю их доступными с помощью аннотации @PropertySource.

@Configuration
@PropertySource("classpath:default.properties")
public class DefaultConfig {}

Затем я хочу переопределить значение test=override, которое находится в другом файле свойств в классе OverrideConfig, поэтому я снова использую @PropertySource.

@Configuration
@Import(DefaultConfig.class)
@PropertySource("classpath:override.properties")
public class OverrideConfig {}

Я настраиваю тест, чтобы доказать, что он работает.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={OverrideConfig.class})
public class TestPropertyOverride {

    @Autowired
    private Environment env;

    @Test
    public void propertyIsOverridden() {
        assertEquals("override", env.getProperty("test"));
    }

}

За исключением, конечно, этого не происходит.

org.junit.ComparisonFailure: expected:<[override]> but was:<[default]>

Максимальное отладка, я вижу, что происходит:

StandardEnvironment:107 - Adding [class path resource [default.properties]] PropertySource with lowest search precedence
StandardEnvironment:107 - Adding [class path resource [override.properties]] PropertySource with lowest search precedence

Кажется назад. Я делаю простую ошибку или тупо это, или вы ожидаете, что свойства, определенные @PropertySource в классе конфигурации @Import-ed, будут переопределены свойствами, определенными в am @PropertySource в классе @Import-ing?

Ответ 1

Вот решение Helder Sousa, написанное как комментарий проблема JIRA, созданная OP:

[T] поведение, доступное в spring xml (один xml, импортирующий другой xml), можно реализовать с помощью вложенных конфигураций:

@Configuration
@PropertySource("classpath:default.properties")
public class DefaultConfig {}
@Configuration
@PropertySource("classpath:override.properties")
public class OverrideConfig {

    @Configuration
    @Import(DefaultConfig.class)
    static class InnerConfiguration {}

}

С помощью этой настройки свойства будут собраны в правильном порядке.

Ответ 2

Сегодня с помощью Spring 4 вы можете использовать это:

@TestPropertySource(value="classpath:/config/test.properties")

И это можно использовать для использования и, в конечном счете, переопределения свойств для теста junit:

@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(value="classpath:/config/test.properties")

Ответ 3

В настоящее время я боюсь с аналогичным случаем в Spring 3.1, но я использую другой подход для переопределения свойств, потому что @PropertySource не поддерживает дополнительные файлы свойств:

@Configuration
@PropertySource("classpath:default.properties")
public class BaseConfig {

  @Inject
  private ApplicationContext context;

  @PostConstruct
  public void init() throws IOException {
    Resource runtimeProps = context.getResource("classpath:override.properties");
    if (runtimeProps.exists()) {
      MutablePropertySources sources = ((ConfigurableApplicationContext) context).getEnvironment().getPropertySources();
      sources.addFirst(new ResourcePropertySource(runtimeProps));
    }
  }
...

Похоже, что @Import не вызывает никакого конкретного порядка создания @Configuration, кроме порядка, определяемого нормальными зависимостями bean. Способ принудительного такого порядка состоит в том, чтобы ввести базовый экземпляр @Configuration сам по себе в качестве зависимости. Не могли бы вы попробовать:

@Configuration
@Import(DefaultConfig.class)
@PropertySource("classpath:override.properties")
public class OverrideConfig {

  @Inject
  private DefaultConfig defaultConfig;

  ...
}

Помогает ли это? И, возможно, новая аннотация ContextHierarchy может быть полезной и здесь, но я не пробовал этот вариант до сих пор.

Ответ 4

Вы можете обеспечить порядок загрузки своих свойств следующим образом:

@Configuration
@PropertySource(value={"classpath:default.properties","classpath:override.properties"})
public class OverrideConfig {
...
}

Ответ 5

У меня была аналогичная проблема, и мне удалось просто объявить свойство по умолчанию в моей настраиваемой конфигурации:

@Configuration
@Import(DefaultConfig.class)
@PropertySource({"classpath:default.properties", "classpath:override.properties"})
public class OverrideConfig {}