Spring上下文动态变化
我已经读过动态bean定义的变化。 我在一个简单的代码示例中尝试它(参见下面的代码),我发现它在我不想停止服务器但添加/更改bean定义的情况下非常有吸引力。
问题:
- 这样做是否安全(见下面的代码)?
-
我已经读过在
StaticApplicationContex
或BeanPostProcessor
或BeanFactoryPostProcessor
帮助下,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")); } }
编辑:
你能否回答以下问题:
- 据我所知,
BeanPostProcess
允许您通过使用代理包装对象来在运行时修改已存在的bean实例。 我对吗? -
AbstractApplicationContext#refresh()删除所有单例bean并重新创建它们。
- 但是如果我想改变prototype / custom scoped bean的定义呢?
- 如果我有两个bean:A和B.A引用B.如果我以不包含B的定义的方式更改bean定义.B实例将被销毁,但新实例不会被创造。 比A将获得
null
依赖。 我对吗?
-
StaticApplicationContext
和BeanFactoryPostProcessor
都允许我在运行时更改bean定义。 但有什么区别,利弊? - [主要问题]为什么Spring有3种机制来实现同一目标。 您能否在
AbstractApplicationContext#refresh()
,StaticApplicationContext
和BeanFactoryPostProcessor
之间进行简单的比较(或用例示例)。
这样做是否安全(见下面的代码)?
你必须定义安全 。
AbstractApplicationContext#refresh()
方法javadoc声明
由于这是一个启动方法,它应该销毁已创建的单例,如果它失败,以避免悬空资源。 换句话说,在调用该方法之后,应该实例化所有单个或不单个。
基本上,上下文中的每个bean都将被销毁,并且所有对它们的引用都将被删除,这使它们成为垃圾收集的候选者。 您需要确保这些bean有适当的方法来释放他们可能拥有的任何资源。 有不同的方法可以做到这一点
- 使您的类实现
DisposableBean
接口。 - 将
destroy-method
属性添加到
或@Bean
定义中。 - 使用
@PreDestroy
注释方法。
请注意, refresh()
通常会急切地刷新ApplicationContext
,即。 立即重新实例化所有bean。 在发生这种情况时,您可能会发现应用程序有些速度变慢。
我已经读过可以借助
StaticApplicationContext
或BeanPostProcessor
或BeanFactoryPostProcessor
在运行时实现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
除非您明确告诉它。
StaticApplicationContext
和BeanFactoryPostProcessor
都允许我在运行时更改bean定义。 但有什么区别,利弊?
两者完全不同。 StaticApplicationContext
是一个ApplicationContext
实现。 在这里,您声明了bean定义。 BeanFactoryPostProcessor
用于根据您要实现的任何条件以任何方式修改这些bean定义。
为什么Spring有3种机制来实现相同的目标。 您能否在
AbstractApplicationContext#refresh()
,StaticApplicationContext
和BeanFactoryPostProcessor
之间进行简单的比较(或使用示例)。
目标不一样。 ApplicationContext
与BeanFactoryPostProcessor
不同,并且在上下文生命周期的不同时间发挥作用(请参阅上一个问题中的漂亮图表)。
我没有用例。 了解以上各项可以做什么,并且当您获得特定要求时,您将知道何时应用它们。