Spring上下文动态变化

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

问题:

  1. 这样做是否安全(见下面的代码)?
  2. 我已经读过在StaticApplicationContexBeanPostProcessorBeanFactoryPostProcessor帮助下, StaticApplicationContex在运行时实现bean定义更改? 那么区别是什么呢?

     public class Main { final static String header = "\n" + "\n" + " \n" + " "; final static String contextA = "\n" + "\t\t\n" + ""; final static String contextB = "\n" + "\t\t\n" + ""; 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")); } } 

编辑:

你能否回答以下问题:

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

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

  4. [主要问题]为什么Spring有3种机制来实现同一目标。 您能否在AbstractApplicationContext#refresh()StaticApplicationContextBeanFactoryPostProcessor之间进行简单的比较(或用例示例)。

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

你必须定义安全

AbstractApplicationContext#refresh()方法javadoc声明

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

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

  • 使您的类实现DisposableBean接口。
  • destroy-method属性添加到@Bean定义中。
  • 使用@PreDestroy注释方法。

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

我已经读过可以借助StaticApplicationContextBeanPostProcessorBeanFactoryPostProcessor在运行时实现bean定义更改? 那么区别是什么呢?

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

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

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

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

最后, BeanPostProcessor不会更改bean定义。 您可以使用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更改它,或在上下文配置中以不同方式声明它。

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

StaticApplicationContextBeanFactoryPostProcessor都允许我在运行时更改bean定义。 但有什么区别,利弊?

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

为什么Spring有3种机制来实现相同的目标。 您能否在AbstractApplicationContext#refresh()StaticApplicationContextBeanFactoryPostProcessor之间进行简单的比较(或使用示例)。

目标不一样。 ApplicationContextBeanFactoryPostProcessor不同,并且在上下文生命周期的不同时间发挥作用(请参阅上一个问题中的漂亮图表)。

我没有用例。 了解以上各项可以做什么,并且当您获得特定要求时,您将知道何时应用它们。