2010-06-14 1 views
52

То, что я хотел бы достичь, это возможность «динамически» (то есть на основе свойства, определенного в файле конфигурации) включить/отключить импорт дочернего контекста Spring XML.Как добиться условного импорта ресурсов в контексте Spring XML?

Я представляю себе что-то вроде:

<import condition="some.property.name" resource="some-context.xml"/> 

Если свойство разрешен (в булево), и когда истинный контекст импортируется, в противном случае это не так.

Некоторые из моих исследований до сих пор:

  • Написание пользовательских NamespaceHandler (и связанные с ним классы), так что я могу зарегистрировать свой собственный элемент в моем собственном пространстве имен. Например: <myns:import condition="some.property.name" resource="some-context.xml"/>

    Проблема с этим подходом заключается в том, что я не хочу реплицировать всю логику импорта ресурсов из Spring, и для меня не очевидно, что мне нужно делегировать для этого.

  • Переопределение DefaultBeanDefinitionDocumentReader для расширения поведения синтаксического анализа и интерпретации элемента «импорт» (что происходит там в методе importBeanDefinitionResource). Однако я не уверен, где я могу зарегистрировать это расширение.
+0

Вместо того, чтобы выполнять условный импорт, почему бы не использовать сканирование путей класса и не использовать только требуемую конфигурацию? Я считаю, что условный импорт более сложный, и сложнее определить, что/не настроено при просмотре развернутого приложения. – SteveD

+0

Как определить «требуемую конфигурацию»? У нас есть части функциональности, которые хорошо модулярны и автоматически активируются при загрузке контекста (шаблон доски). Но нам нужен механизм для динамического (чтение: при установке/настройке времени) активировать и деактивировать эти функции. Это своего рода легкая система плагинов. –

ответ

37

Ближайшие вы можете получить, используя стандартные компоненты пружины:

<import resource="Whatever-${yyzzy}.xml"/> 

где ${xyzzy} интерполяцию свойства из свойств системы. (Я использую взломанную пользовательскую версию класса загрузчика контекста, которая добавляет свойства из других мест в объект свойств системы до начала процесса загрузки.)

Но вы также можете уйти с импортом большого количества ненужных вещей ... и используйте различные трюки, чтобы вызвать создание необходимых компонентов. Эти приемы включают в себя:

  • заполнитель и подмена свойства
  • выбор различных бобов с использованием нового языка выражений Spring,
  • боба алиасов с заполнителями в целевом имени,
  • ленивой инициализацию боба и
  • умные фабрики фасоли.
+0

Я не хочу на самом деле касаться контекста рассматриваемого модуля и предотвращать создание экземпляра компонента таким образом. Я действительно хотел бы сохранить границу контекста для модуля и переключиться на этот уровень. Я рассмотрел заменитель свойств для URI ресурса, но, как вы сказали, учитываются только системные свойства, и он позволяет мне переключиться на другой контекст, а не отключать его. Возможно, мне пришлось бы предоставить общий, пустой «disabled-module-context.xml»? –

+0

@Boris - вот что я делаю. Взгляните на проект «metadata-net» на SourceForge и посмотрите, как работают конфигурации Danno/Emmet/Chico. Это пока что-то работа, но вы могли бы заимствовать некоторые идеи. –

+6

Это работает только для свойств системы. Свойства из хранилища контекстного пространства еще не загружены при импорте. (http://stackoverflow.com/questions/5253546/are-properties-read-by-a-spring-property-placeholder-immediately-available) –

21

Для записи Роберт Малдон объясняет, как выполнить условное определение фасолей в этом сообщении: http://robertmaldon.blogspot.com/2007/04/conditionally-defining-spring-beans.html. Это немного длиннее, чтобы скопировать его здесь (кроме того, я не думаю, что мне все равно придется копировать его статью).

Конечный результат этого подхода, адаптированный для примера, является:

<condbean:cond test="${some.property.name}"> 
    <import resource="some-context.xml"/> 
</condbean:cond> 

Это, конечно, не так просто, как решение Стивена C, но это гораздо более poweful.

22

С Spring 3.1.x вы можете использовать bean profiles для достижения условного импорта ресурсов и создания экземпляра bean.Это, конечно, не поможет, если вы используете более раннюю версию :)

21

Как упоминалось ранее, это может быть легко достигнуто с профилями, если вы используете Spring 3.1+

<!-- default configuration - will be loaded if no profile is specified --> 
<!-- This will only work if it's put at the end of the configuration file --> 
<!-- so no bean definitions after that --> 
<beans profile="default"> 
    <import resource="classpath:default.xml" /> 
</beans> 
<!-- some other profile --> 
<beans profile="otherProfile"> 
    <import resource="classpath:other-profile.xml" /> 
</beans> 

otherProfile может быть легко активируется, например,

mvn install -Dspring.profiles.active=otherProfile 

, если вы используете разные профили в тестах, просто добавьте -DforkMode=never, чтобы убедиться, что тесты будут работать внутри одной виртуальной машины, поэтому Парам spring.profiles.active обыкновение теряться

+0

Профили отличные, но как насчет вызова другой реализации условия? Это возможно? –

0

Другим вариантом является приложение загрузите файл modules-config.xml, который находится в папке/conf, и отредактируйте его на этапе установки/конфигурации, чтобы раскомментировать модули, которые вы хотите загрузить.

Это решение, которое я использую с веб-приложением, которое служит контейнером для различных модулей интеграции. Веб-приложение распространяется со всеми различными модулями интеграции. Модуль-config.xml помещается в папку tomcat/conf, а папка conf добавляется в путь к классам (через свойство catalina.properties/common.loader). В моем веб-приложении webapp-config.xml есть <import resource="classpath:/modules-config.xml"/>, чтобы загрузить его.

0

Еще один рассмотреть для Spring 3.0:

<alias name="Whatever" alias=""Whatever-${yyzzy}" /> 

где ${xyzzy} интерполяцию свойство из свойств системы.

18

Это теперь вполне возможно, с использованием Spring 4.

В вашей основной файл содержимого приложения

<bean class="com.example.MyConditionalConfiguration"/> 

И MyConditionalConfiguration выглядит

@Configuration 
@Conditional(MyConditionalConfiguration.Condition.class) 
@ImportResource("/com/example/context-fragment.xml") 
public class MyConditionalConfiguration { 
    static class Condition implements ConfigurationCondition { 
     @Override 
     public ConfigurationPhase getConfigurationPhase() { 
      return ConfigurationPhase.PARSE_CONFIGURATION; 
     } 
     @Override 
     public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 
      // only load context-fragment.xml if the system property is defined 
      return System.getProperty("com.example.context-fragment") != null; 
     } 
    } 
} 

И, наконец, вы положить определения компонентов, которые вы хотите включить в /com/example/context-fragment.xml

См. JavaDoc for @Conditional

+0

Очень круто! Спасибо за обновление после всего этого времени. Рад, что они, наконец, что-то сделали для этого. –

+0

Мы также не можем получить местозаполнитель. Можно использовать только System.property. –

+0

Исходный вопрос касался только условного импорта, а не использования заполнителей. Так что это на самом деле правильный ответ. – Jakub

Смежные вопросы