将动态Bean添加到Spring Web上下文

7

我需要能够在Spring Web上下文中添加新的bean(在任何作用域中),这些类可能在编译时被定义,也可能没有。

例如,我可以动态创建一些类,然后为该类注册单例或会话bean。

我读了一些有关BeanFactoryPostProcessor的内容,但不确定它是否适用于Web上下文,如果我理解正确,它只能在实际加载bean实例之前工作,而不能在之后,我错了吗?

我还没有找到有关如何在AnnotationConfigWebApplicationContext中执行此操作的信息,在我的测试中,所有我动态创建的bean都没有注入到其他实例中,即使它们被注入了,我也只看到了注册Singleton bean的方法,而不是其他作用域的方法:

ctx.getBeanFactory().registerSingleton("dummy", dummy);

我发现了这个问题:Spring中的动态创建Bean,但是当我尝试像这样将任何bean、bean定义或bean定义构建器添加到Web上下文中时,bean并没有被加载:
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.setServletContext(servletContext);
ctx.refresh();
//
log.trace("Registering first test bean");
Test test = new Test();
test.setDummy("x1");
ctx.getBeanFactory().registerSingleton("myTestBean1", test);        

log.trace("Registering second test bean");
BeanDefinition testDef = new RootBeanDefinition(Test.class);        
testDef.setScope(BeanDefinition.SCOPE_SINGLETON);        
ctx.getBeanFactory().registerSingleton("myTestBean2", testDef);

Test dummy1 = (Test)ctx.getBean("myTestBean1");
Object dummy2 = ctx.getBean("myTestBean2");

log.trace("beans: 1: {}; 2: {}", dummy1, dummy2); //<--this works, but...
ctx.refresh();

ctx.register(MyConfig.class); //configuring other beans

当我从另一个在MyConfig.class内配置或用@Component注解配置的bean(它甚至可能是另一个动态组件)执行此操作时:

@Autowire Test myTestBean1;
//Or this:
Object a = this.ctx.getBean("myTestBean1"); //Or myTestBean2

它会抛出一个NoSuchBeanDefinitionException异常。

请帮帮我!我已经看了很多东西,但没有找到任何有用的信息,或者可能我找到了,但在短时间内无法测试我在网上找到的所有内容,而且Spring文档似乎只适用于普通情况和XML配置,而不适用于我正在尝试做的这些疯狂的事情,也不适用于编程式配置。


我在想,是否在Java代码中明确处理对象生命周期会使事情变得更简单。 - Nicola Musatti
1个回答

3
抱歉,您想实现的内容是无法完成的。自动装配发生在bean最初创建时。在您的情况下,您希望在将bean添加到工厂之前就将其连接起来,这当然行不通 - Spring无法进行时间旅行。
我认为您想要的是工厂模式。在Spring中,您可以将bean的实例化推迟到通过实现FactoryBean创建的工厂中。在此处阅读更多信息:FactoryBean

谢谢,但在这个例子中,我是先创建Bean,然后再在另一个Bean中进行自动装配。我编辑了问题以使其更清晰。虽然看起来很有趣,但如果需要另一种方法,我会仔细研究一下这个。 - Frank Orellana
在您的示例中,第二行首先调用ctx.refresh(),这将构建整个bean工厂并处理所有自动装配。这发生在您执行任何其他操作之前。无论如何,在运行时手动插入bean都不是Spring的预期工作方式。我相信您可以通过某种方式使其正常运行,但它并不会很好看。如果需要延迟/推迟bean创建,则应使用范围和/或工厂和接口来处理。 - pap
如果我在之前不调用refresh方法,就会抛出IllegalStateException异常。我检查了代码并验证了在注册新的单例时工厂不为null。工厂的问题在于我仍然需要定义bean的名称,以便Spring将创建委托给工厂。我已经没有更多的想法了 :( - Frank Orellana
@Lando 不要与框架对抗,要与之合作。你试图做的事情与 Spring 的意图和设计相反。多花一点时间思考每个对象的生命周期以及你想要做什么,你会发现你无法继续下去的原因是因为你的基本前提是错误的。 - pap
正确的博客文章链接似乎是 http://spring.io/blog/2011/08/09/what-s-a-factorybean - pimlottc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接