Динамическое изменение контекста Spring

Я прочитал, что динамическое изменение определения bean. Я пробую это в простом примере кода (см. код ниже), и я нахожу его очень привлекательным в ситуациях, когда я не хочу останавливать сервер, но добавлять/изменять определение bean.

вопросы:

  1. безопасно ли это сделать (см. код ниже)?
  2. я читал, что можно добиться изменения определения 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:

можете ли вы ответить на вопросы ниже:

  1. как я понимаю BeanPostProcess позволяет изменять уже существующие экземпляры bean во время выполнения путем обертывания объекта прокси-сервером. Я прав?
  2. AbstractApplicationContext#refresh () отбросьте все одноэлементные бобы и воссоздайте их.

    • но если я хочу изменить определение prototype / custom scoped bean?
    • если у меня есть два компонента: A и B. A имеет ссылку на B. Если я изменю определение компонента таким образом, что оно не содержит определения B. чем экземпляры B будут уничтожены, но новые экземпляры не будут созданы. Чем A получит null зависимость. Я прав?
  3. StaticApplicationContext и BeanFactoryPostProcessor оба позволяют мне изменить определение bean в во время выполнения. Но в чем разница, плюсы/минусы?

  4. [главный вопрос] Почему весна имеет 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 и вступает в игру в другое время в контексте жизненного цикла (см. Этот хороший график, который у вас был в предыдущем вопросе).

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