以编程方式将 Bean 添加到 Spring Web App 上下文
Posted
技术标签:
【中文标题】以编程方式将 Bean 添加到 Spring Web App 上下文【英文标题】:Add Bean Programmatically to Spring Web App Context 【发布时间】:2011-05-31 06:07:24 【问题描述】:由于是插件架构,我正在尝试以编程方式将 bean 添加到我的 web 应用程序中。我有一个通过@Component
注释创建的Spring bean,我正在实现ApplicationContextAware
接口。
我的覆盖函数如下所示:
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException
// this fails
this.applicationContext = (GenericWebApplicationContext) applicationContext;
基本上,我不知道如何将 bean 添加到给 setApplicationContext 的 applicationContext 对象。谁能告诉我我是怎么搞错的?
好的,这就是我最终得到的解决方案:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry bdr)
throws BeansException
BeanDefinition definition = new RootBeanDefinition(
<My Class>.class);
bdr.registerBeanDefinition("<my id>", definition);
【问题讨论】:
【参考方案1】:首先初始化属性值
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
mutablePropertyValues.add("hostName", details.getHostName());
mutablePropertyValues.add("port", details.getPort());
DefaultListableBeanFactory context = new DefaultListableBeanFactory();
GenericBeanDefinition connectionFactory = new GenericBeanDefinition();
connectionFactory.setBeanClass(Class);
connectionFactory.setPropertyValues(mutablePropertyValues);
context.registerBeanDefinition("beanName", connectionFactory);
添加到 bean 列表
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
beanFactory.registerSingleton("beanName", context.getBean("beanName"));
【讨论】:
【参考方案2】:为什么需要GenericWebApplicationContext
类型?
我认为您可能可以使用任何 ApplicationContext 类型。
通常你会使用一个 init 方法(除了你的 setter 方法):
@PostConstruct
public void init()
AutowireCapableBeanFactory bf = this.applicationContext
.getAutowireCapableBeanFactory();
// wire stuff here
您可以使用任一方法连接 bean
AutowireCapableBeanFactory.autowire(Class, int mode, boolean dependencyInject)
或
AutowireCapableBeanFactory.initializeBean(Object existingbean, String beanName)
【讨论】:
当我这样做时,它不会将它们添加到 ApplicationContext【参考方案3】:实际上AnnotationConfigApplicationContext
派生自AbstractApplicationContext
,其中有空的postProcessBeanFactory
方法可供覆盖
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
要利用这一点,请创建如下所示的 AnnotationConfigApplicationContextProvider
类(给定 Vertx
实例示例,您可以改用 MyClass
)...
public class CustomAnnotationApplicationContextProvider
private final Vertx vertx;
public CustomAnnotationApplicationContextProvider(Vertx vertx)
this.vertx = vertx;
/**
* Register all beans to spring bean factory
*
* @param beanFactory, spring bean factory to register your instances
*/
private void configureBeans(ConfigurableListableBeanFactory beanFactory)
beanFactory.registerSingleton("vertx", vertx);
/**
* Proxy method to create @link AnnotationConfigApplicationContext instance with no params
*
* @return @link AnnotationConfigApplicationContext instance
*/
public AnnotationConfigApplicationContext get()
return new AnnotationConfigApplicationContext()
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
;
/**
* Proxy method to call @link AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(DefaultListableBeanFactory) with our logic
*
* @param beanFactory bean factory for spring
* @return
* @see AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(DefaultListableBeanFactory)
*/
public AnnotationConfigApplicationContext get(DefaultListableBeanFactory beanFactory)
return new AnnotationConfigApplicationContext(beanFactory)
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
;
/**
* Proxy method to call @link AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(Class[]) with our logic
*
* @param annotatedClasses, set of annotated classes for spring
* @return
* @see AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(Class[])
*/
public AnnotationConfigApplicationContext get(Class<?>... annotatedClasses)
return new AnnotationConfigApplicationContext(annotatedClasses)
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
;
/**
* proxy method to call @link AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...) with our logic
*
* @param basePackages set of base packages for spring
* @return
* @see AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
*/
public AnnotationConfigApplicationContext get(String... basePackages)
return new AnnotationConfigApplicationContext(basePackages)
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
super.postProcessBeanFactory(beanFactory);
configureBeans(beanFactory);
;
在创建ApplicationContext
时,您可以使用
Vertx vertx = ...; // either create or for vertx, it'll be passed to main verticle
ApplicationContext context = new CustomAnnotationApplicationContextProvider(vertx).get(ApplicationSpringConfig.class);
【讨论】:
【参考方案4】:这是一个简单的代码:
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
beanFactory.registerSingleton(bean.getClass().getCanonicalName(), bean);
【讨论】:
你能详细说明答案吗?【参考方案5】:在 Spring 3.0 中,您可以使您的 bean 实现 BeanDefinitionRegistryPostProcessor
并通过 BeanDefinitionRegistry
添加新 bean。
在以前的 Spring 版本中,您可以在 BeanFactoryPostProcessor
中执行相同的操作(尽管您需要将 BeanFactory
强制转换为 BeanDefinitionRegistry
,这可能会失败)。
【讨论】:
谢谢。我想最难的部分是知道要寻找什么。 请注意JavaDoc:A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects. If bean instance interaction is required, consider implementing BeanPostProcessor instead.
BeanDefinitionRegistryPostProcessor
怎么办?假设我写了这个类。接下来是什么?如何激活它?以上是关于以编程方式将 Bean 添加到 Spring Web App 上下文的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式将“@Cascade”添加到 POJO 字段(Spring mvc + Hibernate)
如何以编程/动态方式将组件添加到 p:dataTable facet
可以在加载的 Spring 上下文中以编程方式替换 Spring Bean