Spring上下文动态变化 [英] Spring context dynamic change

查看:69
本文介绍了Spring上下文动态变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了动态bean定义的更改.我在一个简单的代码示例中进行了尝试(请参见下面的代码),并且在不想停止服务器但添加/更改bean定义的情况下,它非常吸引人.

I've read that dynamic bean definition change. I try it in a simple code example (see code below), and I find it very attractive in situations where I don't want to stop server but add/change bean definition.

问题:

Questions:

  1. 这样做安全吗(请参见下面的代码)?
  2. 我已经读到可以借助StaticApplicationContexBeanPostProcessorBeanFactoryPostProcessor在运行时实现Bean定义更改吗?那有什么区别?

  1. Is it safe do to so (see code below)?
  2. I've read that it is possible to achieve bean definition change in runtime with help of StaticApplicationContex or BeanPostProcessor or BeanFactoryPostProcessor? So what is the difference?

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"));
}
}

您能回答以下问题吗?

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

  1. As I understand BeanPostProcess allow you to modify already existed bean instances at runtime by wrapping the object with proxy. Am I right?
  2. AbstractApplicationContext#refresh() drop all singleton beans and recreate them.

  • 但是,如果我想更改原型/自定义范围的bean的定义?
  • 如果我有两个bean:A和B.A引用了B.如果我以不包含B的定义的方式更改bean的定义.B实例将被销毁,但是新实例将被销毁将不会被创建.比A将得到null依赖关系.我说的对吗?
  • But If I want to change the definition of prototype/custom scoped bean?
  • If I've got two beans: A and B. A has reference to B. If I change the bean definition in such way that it doesn't contain definition of B. Than B instances will be destroyed, but new instances won't be created. Than A will get a null dependency. Am I right?

StaticApplicationContextBeanFactoryPostProcessor都允许我在运行时更改bean定义.但是,优点/缺点有什么区别?

StaticApplicationContext and BeanFactoryPostProcessor both allow me to change a bean definition in runtime. But what are the difference, pros/cons?

推荐答案

这样做安全吗(请参见下面的代码)?

Is it safe do to so (see code below)?

您必须定义安全.

AbstractApplicationContext#refresh()方法的javadoc状态

The AbstractApplicationContext#refresh() method javadoc states

由于这是一种启动方法,因此应销毁已创建的方法 如果失败,则单身人士,以避免资源悬而未决.换一种说法, 调用该方法后,所有单例或根本没有单例 应该实例化.

As this is a startup method, it should destroy already created singletons if it fails, to avoid dangling resources. In other words, after invocation of that method, either all or no singletons at all should be instantiated.

基本上,您上下文中的每个bean都将被销毁,对它们的所有引用都将被删除,从而使其成为垃圾回收的候选对象.您需要确保这些bean具有释放它们可能拥有的任何资源的适当方法.

Basically every bean in your context will be destroyed and all references to them will be dropped, making them candidates for garbage collection. You need to make sure that those beans have appropriate ways to release any resources they might have. There are different ways to do that

  • 使您的类实现DisposableBean接口.
  • <bean>@Bean定义中添加destroy-method属性.
  • 使用@PreDestroy注释方法.
  • Make your class implement the DisposableBean interface.
  • Add a destroy-method attribute to your <bean> or @Bean definition.
  • Annotate a method with @PreDestroy.

请注意,refresh()通常会急切地刷新您的ApplicationContext,即.立即重新实例化所有咖啡豆.在这种情况下,您可能会注意到应用程序速度变慢.

Note that refresh() will typically eagerly refresh your ApplicationContext, ie. re-instantiate all the beans immediately. You may notice some slow down in your application while that happens.

我读到有可能实现Bean定义更改 在StaticApplicationContextBeanPostProcessor的帮助下运行 BeanFactoryPostProcessor?那有什么区别?

I've read that it is possible to achieve bean definition change in runtime with help of StaticApplicationContext or BeanPostProcessor or BeanFactoryPostProcessor? So what is the difference?

StaticApplicationContext是您自己注册Bean定义的ApplicationContext类之一.在您的示例中,bean定义是从XML文件中解析出来的,并在后台注册.使用 StaticApplicationContext ,则使用

StaticApplicationContext is one of the ApplicationContext classes where you register the bean definitions yourself. In your example, the bean definitions are parsed from your XML file and registered behind the scenes. With StaticApplicationContext, you use registerBeanDefinition(..) or the other registerXxx() methods to explicitly register a bean definition.

A BeanFactoryPostProcessor可以访问正在使用的BeanFactory,因此可以访问所有已注册的bean定义.这样,您可以检索所需的任何BeanDefinition并对其进行修改.作为

A BeanFactoryPostProcessor has access to the BeanFactory being used and therefore all the bean definitions that have been registered. As such, you can retrieve any BeanDefinition you want and modify it. As the javadoc for BeanFactoryPostProcess#postProcessBeanFactory(..) states

所有bean定义都将被加载,但是没有bean将具有 被实例化了.这允许覆盖或添加属性 甚至渴望初始化bean.

All bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for overriding or adding properties even to eager-initializing beans.

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

You can change the bean definition before the ApplicationContext actually uses it.

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

Finally, a BeanPostProcessor doesn't change the bean definition. You can use a BeanPostProcessor to change how a bean is created but the underlying BeanDefinition will stay the same.

供您编辑(比实际答案要大:))

For your edit (which is bigger than the actual answer :) )

据我了解,BeanPostProcess允许您修改已经存在的 通过使用代理包装对象,在运行时生成Bean实例.我是吗 对吧?

As I understand BeanPostProcess allow you to modify already existed bean instances at runtime by wrapping the object with proxy. Am I right?

这不仅用于代理,您还可以对对象进行任何操作:修改其属性,在其他上下文中注册它,使其成为null,等等.这涉及bean定义.

It's not just for proxying, you can do anything you want with the object: modify its properties, register it in some other context, make it null, etc. This goes around the bean definition.

AbstractApplicationContext#refresh()删除所有单例豆,然后 重新创建它们.

AbstractApplicationContext#refresh() drop all singleton beans and recreate them.

但是如果我想更改原型/自定义范围的定义 豆角,扁豆?如果我有两个豆:A和B.A引用了B.如果我 以不包含以下内容的方式更改Bean定义 B的定义.B实例将被销毁,但新实例将被销毁 将不会被创建.比A将获得一个空的依赖关系.我说的对吗?

But If I want to change the definition of prototype/custom scoped bean? If I've got two beans: A and B. A has reference to B. If I change the bean definition in such way that it doesn't contain definition of B. Than B instances will be destroyed, but new instances won't be created. Than A will get a null dependency. Am I right?

ApplicationContext中,声明您的bean定义.如果要更改Bean定义,请在BeanFactoryPostProcessor中对其进行更改,或者在上下文配置中对其进行不同的声明.

In an ApplicationContext, you declare your bean definitions. If you're going to change a bean definition, change it in a BeanFactoryPostProcessor or declare it differently in the context configuration.

对于依赖项,如果破坏了B bean定义,则不会将任何bean注入A中,并且Spring会抱怨并抛出NoSuchBeanDefinitionException.除非您明确告知,否则Bean注入永远不会注入null.

For dependencies, if you destroy the B bean definition, there won't be a bean to inject into A and Spring will complain, throwing NoSuchBeanDefinitionException. Bean injection never injects null unless you explicitly tell it to.

StaticApplicationContextBeanFactoryPostProcessor都允许我 在运行时更改bean定义.但是有什么区别 优点/缺点?

StaticApplicationContext and BeanFactoryPostProcessor both allow me to change a bean definition in runtime. But what are the difference, pros/cons?

两者的作用完全不同. StaticApplicationContextApplicationContext的实现.在这里,您声明了bean定义. BeanFactoryPostProcessor用于根据您希望实现的任何条件以任何方式修改这些bean定义.

The two serve completely different purposes. StaticApplicationContext is an ApplicationContext implementation. Here, you declare bean definitions. A BeanFactoryPostProcessor serves to modify those bean definitions in any way, based on whatever condition you care to implement.

为什么Spring有3种机制来实现相同的目标.你能做一个 之间的简要比较(或用例示例) AbstractApplicationContext#refresh()StaticApplicationContextBeanFactoryPostProcessor,请.

Why Spring has 3 mechanism to achieve the same goal. Can you make a brief comparison (or usecases examples) between AbstractApplicationContext#refresh(), StaticApplicationContext and BeanFactoryPostProcessor please.

目标不一样. ApplicationContextBeanFactoryPostProcessor不同,它在上下文生命周期的不同时间起作用(请参见您在上一个问题中获得的漂亮图表).

The goal is not the same. An ApplicationContext is different than a BeanFactoryPostProcessor and comes into play at a different time in the context life cycle (see that nice graph you had in a previous question).

我没有适合您的用例.了解以上每种方法可以做什么,并且在满足特定要求时会知道何时应用它们.

I don't have use cases for you. Learn what each of the above can do and you'll know when to apply them when you get specific requirements.

这篇关于Spring上下文动态变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆