【问题标题】:Add Bean Programmatically to Spring Web App Context以编程方式将 Bean 添加到 Spring Web App 上下文
【发布时间】: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);
}

【问题讨论】:

    标签: java spring web-applications dynamic


    【解决方案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 怎么办?假设我写了这个类。接下来是什么?如何激活它?
        猜你喜欢
        • 2017-08-18
        • 2015-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-24
        • 2010-12-29
        • 1970-01-01
        相关资源
        最近更新 更多