Как добиться условного импорта ресурсов в контексте Spring XML?
то, что я хотел бы достичь, - это возможность "динамически" (т. е. на основе свойства, определенного в файле конфигурации) включить/отключить импорт дочернего контекста XML Spring.
Я представляю себе что-то вроде:
<import condition="some.property.name" resource="some-context.xml"/>
где свойство разрешается (в логическое значение) и когда true импортируется контекст, в противном случае это не так.
некоторые из моих исследований до сих пор:
-
написание пользовательского NamespaceHandler (и связанные классов), поэтому я могу зарегистрировать свой собственный пользовательский элемент в своем собственном пространстве имен. Например:
<myns:import condition="some.property.name" resource="some-context.xml"/>
проблема с этим подходом заключается в том, что я не хочу реплицировать всю логику импорта ресурсов из Spring, и для меня не очевидно, что мне нужно делегировать для этого.
- переопределение
DefaultBeanDefinitionDocumentReader
чтобы расширить поведение разбора и интерпретации элемента "импорт" (что происходит там вimportBeanDefinitionResource
метод). Однако я не уверен, где я могу зарегистрироваться это расширение.
8 ответов:
теперь это полностью возможно, используя пружину 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; } } }
и затем, наконец, вы помещаете определения bean, которые вы хотите включить в /com/example/context-fragment.xml
посмотреть JavaDoc для @Conditional
самое близкое вы можете получить используя стандартные компоненты весны является следующим:
<import resource="Whatever-${yyzzy}.xml"/>
здесь
${xyzzy}
интерполирует свойство из системных свойств. (Я использую хакерскую пользовательскую версию класса context loader, которая добавляет свойства из других мест в объект свойств системы перед началом процесса загрузки.)но вы также можете уйти с импортом много ненужного хлама ... и используйте различные трюки, чтобы только вызвать необходимые бобы для создания экземпляра. Эти трюки включают в себя:
- заполнитель и замена свойств
- выбор различных бобов с использованием нового языка выражений Spring,
- бобовые псевдонимы с заполнителями в целевом имени,
- инициализация ленивых бобов и
- умные заводы в зернах.
С Весны 3.1.X вы можете использовать профили зерен для достижения условного импорта ресурсов и создания экземпляра компонента. Это конечно не поможет, если вы используете более раннюю версию :)
Как упоминалось ранее, это можно легко сделать с помощью профилей, Если вы используете 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
чтобы убедиться, что тесты будут выполняться внутри той же виртуальной машины, поэтому paramspring.profiles.active
не будут потеряны,
для записи Роберт Мэлдон объясняет, как выполнить условное определение бобов в этом посте: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, но это гораздо больше мощно.
другой вариант-сделать так, чтобы приложение загрузить модули-конфигурация.xml-файл, который находится в папке /conf, и отредактируйте его на этапе установки/конфигурации, чтобы раскомментировать модули, которые вы хотите загрузить.
Это решение, которое я использую с веб-приложением, которое служит контейнером для различных модулей интеграции. Веб-приложение распространяется со всеми различными интеграционными модулями. А модули-конфиг.XML-файле помещается в папку продукта Tomcat /Conf в директории conf добавляется classpath (via catalina.свойства/общие.собственность погрузчик). Мое веб-приложение webapp-config.xml имеет
<import resource="classpath:/modules-config.xml"/>
чтобы загрузить его.
еще один, чтобы рассмотреть для весны 3.0:
<alias name="Whatever" alias=""Whatever-${yyzzy}" />
здесь
${xyzzy}
интерполирует свойство из системных свойств.
вы можете переопределить contextInitialized (javax.сервлет.ServletContextEvent event) в вашем собственном ContextLoaderListener и установите необходимое системное свойство перед super.contextInitialized (событие) называется так
package com.mypackage; import org.springframework.web.context.ContextLoaderListener; public class MyContextLoaderListener extends ContextLoaderListener { public void contextInitialized(javax.servlet.ServletContextEvent event) { System.setProperty("xyz", "import-file-name.xml"); super.contextInitialized(event); } }
и чем заменить ContextLoaderListener на MyContextLoaderListener в вашем интернете.xml
<listener> <listener-class>com.mypackage.MyContextLoaderListener</listener-class> </listener>
Теперь вы можете использовать в вашем весны.xml
<import resource="${xyz}" />
Я надеюсь, что это поможет.