Переопределить default-lazy-init = true для Spring bean определений
Я поддерживаю большую систему Java EE. Большая часть бизнес-логики преобразуется из EJB: s в POJO: s настраивается в нескольких файлах конфигурации контекста spring. EJB: s в основном используются как Facades, который ищет бизнес-логику spring beans из контекста, состоящего из всех файлов конфигурации контекста spring, упомянутых ранее. Для этого мы используем AbstractStatelessSessionBean, снабженный инфраструктурой spring.
Все эти файлы конфигурации имеют директиву по умолчанию-lazy-init = true, а это означает, что бизнес-логика beans не создается, пока они фактически не используются системой. Это предпочтительнее в большинстве случаев, поскольку повторная публикация в режиме разработчика становится быстрее.
Но когда выполняются большие слияния, у нас возникают проблемы с поиском всех ошибок конфигурации, таких как отсутствующие зависимости.
Моя идея - написать некоторую форму теста интеграции с целью найти эти ошибки. Это значит, я думаю, что мне нужно найти способ переопределить все объявления lazy-init = true по умолчанию при создании контекста приложения.
Есть ли какой-либо способ сделать это программно или, возможно, с помощью некоторого тестового файла контекста, который включает все фактические файлы контекста?
Ответы
Ответ 1
Скажем, в настоящее время у вас есть один файл applicationContext.xml
, содержащий все определения bean:
<beans default-lazy-init="true">
<!-- all your beans -->
</beans>
Переименуйте его в applicationContext-main.xml
или что-нибудь и удалите атрибут default-lazy-init="true"
. Теперь создайте два applicationContext.xml
файла:
<beans default-lazy-init="true">
<import resource="applicationContext-core.xml"/>
</beans>
и
<beans default-lazy-init="false">
<import resource="applicationContext-core.xml"/>
</beans>
Как вы видите, единственное различие - это значение default-lazy-init
. Во время разработки ваша команда может использовать прежнюю версию applicationContext.xml
, которая включает в себя все beans с lazy-init
. В средах промежуточной и тестовой среды переключитесь на последнюю, чтобы все beans, включенные в applicationContext-core.xml
создавались с нетерпением.
Ответ 2
Я считаю, что лучший способ контролировать ленивый init beans - оставить по умолчанию lazy-init из всех файлов конфигурации, кроме самого верхнего, как предлагает Tomasz Nurkiewicz. Однако в этом случае мне нужно быстрое и грязное исправление, чтобы проверить все определения bean. (Это немного процесс изменения ленивой политики инициализации.)
Я придумал простой BeanFactoryPostProcessor, который, похоже, выполняет эту работу:
public class NonLazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanName : beanFactory.getBeanDefinitionNames()) {
beanFactory.getBeanDefinition(beanName).setLazyInit(false);
}
}
}
Если он включен в файл контекста, он переопределит ленивый флаг инициализации, заданный любыми включенными файлами контекста.
<beans default-lazy-init="false">
<bean class="example.NonLazyInitBeanFactoryPostProcessor" />
<import resource="applicationContext-core.xml"/>
</beans>
Если я попытаюсь создать контекст из вышеуказанного xml, ошибки конфигурации, ранее скрытые ленивой инициализацией, немедленно появятся в качестве исключений.
Ответ 3
В этом PostProcessor есть один "но"
for (String beanName : beanFactory.getBeanDefinitionNames()) {
beanFactory.getBeanDefinition(beanName).setLazyInit(false);
}
Этот цикл цикла будет перебирать только верхний максимум beans, не включая, например, внутренние (локальные) bean defintions...
Ответ 4
Вы не можете получить доступ к сканеру из контекста - он полностью закрыт, но поскольку вы можете входить в исходный код, вы можете видеть, что нужно для настройки самостоятельно. Я использовал Spring собственный ReflectionTestUtils для установки моего собственного настроенного сканера в контексте:
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
BeanDefinitionDefaults defaults = new BeanDefinitionDefaults();
defaults.setLazyInit(true);
scanner.setBeanDefinitionDefaults(defaults);
ReflectionTestUtils.setField(context, "scanner", scanner);
context.scan("com.some.path");
Вы можете сделать это в любом месте, где есть доступ к Контексту приложения, прежде чем произойдет сканирование компонентов.