Динамическое изменение контекста Spring
Я прочитал, что динамическое изменение определения bean. Я пробую это в простом примере кода (см. код ниже), и я нахожу его очень привлекательным в ситуациях, когда я не хочу останавливать сервер, но добавлять/изменять определение bean.
вопросы:
- безопасно ли это сделать (см. код ниже)?
-
я читал, что можно добиться изменения определения bean во время выполнения с помощью
StaticApplicationContex
илиBeanPostProcessor
илиBeanFactoryPostProcessor
? Так в чем же разница?public class Main { final static String header = "<?xml version="1.0" encoding="UTF-8"?>n" + "<beans xmlns="http://www.springframework.org/schema/beans"n" + " xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"n" + " xmlns:context="http://www.springframework.org/schema/context"n" + " xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">n" + " <context:annotation-config />n" + " <context:component-scan base-package="vbah"/>"; final static String contextA = "<bean id="test" class="java.lang.String">n" + "tt<constructor-arg value="fromContextA"/>n" + "</bean></beans>"; final static String contextB = "<bean id="test" class="java.lang.String">n" + "tt<constructor-arg value="fromContextB"/>n" + "</bean></beans>"; public static void main(String[] args) throws IOException { //create a single context file final File contextFile = new File("src/resources/spring-config.xml"); //write the first context into it FileUtils.writeStringToFile(contextFile, header + contextA); //create a spring context FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext( new String[]{contextFile.getPath()} ); //echo "fromContextA" System.out.println(context.getBean("test")); //write the second context into it FileUtils.writeStringToFile(contextFile, header + contextB); //refresh the context context.refresh(); //echo "fromContextB" System.out.println(context.getBean("test")); } }
EDIT:
можете ли вы ответить на вопросы ниже:
- как я понимаю
BeanPostProcess
позволяет изменять уже существующие экземпляры bean во время выполнения путем обертывания объекта прокси-сервером. Я прав? -
AbstractApplicationContext#refresh () отбросьте все одноэлементные бобы и воссоздайте их.
- но если я хочу изменить определение prototype / custom scoped bean?
- если у меня есть два компонента: A и B. A имеет ссылку на B. Если я изменю определение компонента таким образом, что оно не содержит определения B. чем экземпляры B будут уничтожены, но новые экземпляры не будут созданы. Чем A получит
null
зависимость. Я прав?
StaticApplicationContext
иBeanFactoryPostProcessor
оба позволяют мне изменить определение bean в во время выполнения. Но в чем разница, плюсы/минусы?-
[главный вопрос] Почему весна имеет 3 механизма для достижения той же цели. Можете ли вы сделать краткий compoarison (или использовать примеры) между
AbstractApplicationContext#refresh()
,StaticApplicationContext
иBeanFactoryPostProcessor
пожалуйста.
1 ответов
безопасно ли это сделать (см. код ниже)?
вам придется определить безопасное.
на AbstractApplicationContext#refresh()
метод javadoc состояния
поскольку это метод запуска, он должен уничтожить уже созданный синглеты, если это не удается, чтобы избежать болтающихся ресурсов. Иначе говоря, после вызова этого метода, либо все, либо не используются вообще должен быть создан экземпляр.
в принципе каждый боб в вашем контексте будет уничтожен, и все ссылки на них будут удалены, что сделает их кандидатами на сбор мусора. Вы должны убедиться, что эти бобы имеют соответствующие способы высвобождения любых ресурсов, которые они могут иметь. есть разные способы сделать это
- сделайте свой класс реализовать
DisposableBean
интерфейс. - добавить
destroy-method
атрибут<bean>
или@Bean
определение. - аннотировать метод с
@PreDestroy
.
обратите внимание, что refresh()
обычно охотно обновить ваш ApplicationContext
, ie. немедленно восстановите все бобы. Вы можете заметить некоторое замедление в вашем приложении, пока это происходит.
я читал, что можно добиться изменения определением компонента время выполнения с помощью
StaticApplicationContext
илиBeanPostProcessor
илиBeanFactoryPostProcessor
? Так в чем же разница?
StaticApplicationContext
один из ApplicationContext
классы, в которых вы регистрируете определения Bean-компонентов самостоятельно. В вашем примере определения компонентов анализируются из XML-файла и регистрируются за кулисами. С StaticApplicationContext
, вы используете registerBeanDefinition(..)
и другие registerXxx()
методы явной регистрации определения компонента.
A BeanFactoryPostProcessor
имеет доступ к BeanFactory
используется и, следовательно, все определения bean, которые были зарегистрированы. Таким образом, вы можете получить любой BeanDefinition
вы хотите, и изменить его. Как javadoc для BeanFactoryPostProcess#postProcessBeanFactory(..)
государства
все определения бобов будут загружены, но бобы не будут иметь еще не создан. Это позволяет переопределять или добавлять свойства даже жаждущих инициализации бобы.
вы можете изменить определение bean перед ApplicationContext
на самом деле использует его.
наконец, a BeanPostProcessor
не изменяет определение bean. Вы можете использовать BeanPostProcessor
чтобы изменить способ создания компонента, но базовый BeanDefinition
останется прежним.
для вашего редактирования (которое больше, чем фактический ответ :) )
как я понимаю, BeanPostProcess позволяет вам изменять уже существующие экземпляры bean во время выполнения путем обертывания объекта прокси-сервером. Я правильно?
это не просто проксирование, вы можете делать с объектом все, что хотите: изменять его свойства, регистрировать его в каком-то другом контексте, делать его null
, etc. Это идет вокруг определение фасоли.
AbstractApplicationContext#refresh()
отбросьте все одноэлементные бобы и воссоздать их.но если я хочу изменить определение прототипа / пользовательской области бин? Если у меня есть два боба: A и B. A имеет ссылку на B. Если я измените определение bean таким образом, чтобы оно не содержало определение B. чем B экземпляры будут уничтожены, но новые экземпляры не будет создан. Чем A получит нулевую зависимость. Я правильно?
на ApplicationContext
, вы объявляете свои определения бобов. Если вы собираетесь изменить определение bean, измените его в BeanFactoryPostProcessor
или объявить его по-другому в конфигурации контекста.
для зависимостей, если вы уничтожите B
определение фасоли, не будет фасоли, котор нужно впрыснуть в A
а весна будет жаловаться, бросая NoSuchBeanDefinitionException
. Впрыска фасоли никогда не впрыскивает null
если вы явно не скажете ей об этом.
StaticApplicationContext
иBeanFactoryPostProcessor
оба позволяют мне изменить определение компонента в runtime. Но какая разница?, за / против?
эти два служат совершенно разным целям. StaticApplicationContext
это ApplicationContext
реализация. Здесь вы объявляете определения bean. А BeanFactoryPostProcessor
служит для изменения этих определений bean любым способом, на основе любого условия, которое вы хотите реализовать.
Почему весна имеет 3 механизма для достижения той же цели. Вы можете сделать краткое сравнение (или примеры использования) между
AbstractApplicationContext#refresh()
,StaticApplicationContext
иBeanFactoryPostProcessor
пожалуйста.
цель не та же самая. Ан ApplicationContext
отличается от BeanFactoryPostProcessor
и вступает в игру в другое время в контексте жизненного цикла (см. Этот хороший график, который у вас был в предыдущем вопросе).
у меня нет использование для вас. Узнайте, что может сделать каждый из вышеперечисленных, и вы узнаете, когда их применять, когда получите конкретные требования.