Spring上下文动态变化

VB_*_*VB_ 9 java spring

我已经读过动态bean定义的变化.我在一个简单的代码示例中尝试它(参见下面的代码),我发现它在我不想停止服务器但添加/更改bean定义的情况下非常有吸引力.

问题:

  1. 这样做是否安全(见下面的代码)?
  2. 我已经读过,有可能在运行时通过StaticApplicationContexBeanPostProcessor或帮助实现bean定义更改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" +
                    "\t\t<constructor-arg value=\"fromContextA\"/>\n" +
                    "</bean></beans>";
    
    final static String contextB =
            "<bean id=\"test\" class=\"java.lang.String\">\n" +
                    "\t\t<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"));
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)

编辑:

你能否回答以下问题:

  1. 据我所知,BeanPostProcess允许您通过使用代理包装对象来在运行时修改已存在的bean实例.我对吗?
  2. AbstractApplicationContext#refresh()删除所有单例bean并重新创建它们.

    • 但是如果我想改变prototype/custom scoped bean的定义呢?
    • 如果我有两个bean:A和B. A引用了B.如果我以不包含B的定义的方式更改bean定义.B实例将被销毁,但新实例不会被创造.比A会得到null依赖.我对吗?
  3. StaticApplicationContext并且BeanFactoryPostProcessor都允许我在运行时更改bean定义.但有什么区别,利弊?

  4. [主要问题]为什么Spring有3种机制来实现同一目标.你可以做一个简单的compoarison(或usecases例子)之间AbstractApplicationContext#refresh(),StaticApplicationContextBeanFactoryPostProcessor请.

Sot*_*lis 12

这样做是否安全(见下面的代码)?

你必须定义安全.

AbstractApplicationContext#refresh()方法的javadoc状态

由于这是一个启动方法,它应该销毁已创建的单例,如果它失败,以避免悬空资源.换句话说,在调用该方法之后,应该实例化所有单个或不单个.

基本上,上下文中的每个bean都将被销毁,并且对它们的所有引用都将被删除,这使它们成为垃圾收集的候选者.您需要确保这些bean有适当的方法来释放他们可能拥有的任何资源.有不同的方法可以做到这一点

  • 让你的类实现DisposableBean接口.
  • destroy-method向您的<bean>@Bean定义添加属性.
  • 使用注释方法@PreDestroy.

请注意,refresh()通常会急切地刷新你的ApplicationContext,即.立即重新实例化所有bean.当发生这种情况时,您可能会发现应用程序有些速度变慢.

我已经读过,有可能在运行时通过StaticApplicationContextBeanPostProcessor或 帮助实现bean定义更改BeanFactoryPostProcessor?那么区别是什么呢?

StaticApplicationContextApplicationContext您自己注册bean定义的类之一.在您的示例中,bean定义从XML文件中解析并在后台注册.使用StaticApplicationContext,您可以使用registerBeanDefinition(..)或其他registerXxx()方法显式注册bean定义.

A BeanFactoryPostProcessor可以访问BeanFactory正在使用的内容,因此可以访问已注册的所有bean定义.因此,您可以检索任何BeanDefinition您想要的并修改它.作为BeanFactoryPostProcess#postProcessBeanFactory(..)状态的javadoc

将加载所有bean定义,但尚未实例化任何bean.这允许覆盖或添加属性,甚至是初始化bean.

您可以在ApplicationContext实际使用之前更改bean定义.

最后,a BeanPostProcessor不会改变bean的定义.您可以使用a BeanPostProcessor来更改bean的创建方式,但底层BeanDefinition将保持不变.


对于你的编辑(比实际答案大:))

据我所知,BeanPostProcess允许您通过使用代理包装对象来在运行时修改已存在的bean实例.我对吗?

它不仅仅用于代理,你可以用对象做任何你想要的事情:修改它的属性,在其他一些上下文中注册它,制作它null等等.这就是bean的定义.

AbstractApplicationContext#refresh() 删除所有单例bean并重新创建它们.

但是如果我想改变prototype/custom scoped bean的定义呢?如果我有两个bean:A和B. A引用了B.如果我以不包含B的定义的方式更改bean定义.B实例将被销毁,但新实例不会被创造.比A将获得null依赖.我对吗?

在一个ApplicationContext,你声明你的bean定义.如果您要更改bean定义,请BeanFactoryPostProcessor在上下文配置中更改或以不同方式声明它.

对于依赖项,如果你破坏Bbean定义,就不会有一个bean注入,A而Spring会抱怨,抛出NoSuchBeanDefinitionException.Bean注入永远不会注入,null除非您明确告诉它.

StaticApplicationContext并且BeanFactoryPostProcessor都允许我在运行时更改bean定义.但有什么区别,利弊?

两者完全不同.StaticApplicationContext是一个ApplicationContext实现.在这里,您声明了bean定义.A BeanFactoryPostProcessor用于根据您要实现的任何条件以任何方式修改这些bean定义.

为什么Spring有3种机制来实现同样的目标.你能简单比较(或usecases的例子) AbstractApplicationContext#refresh(),StaticApplicationContextBeanFactoryPostProcessor请.

目标不一样.An ApplicationContext不同于a BeanFactoryPostProcessor并且在上下文生命周期中的不同时间发挥作用(请参阅前一个问题中的漂亮图表).

我没有你的用例.了解上述每项内容可以做什么,并且当您获得特定要求时,您将知道何时应用它们.