当前位置: 首页 > 面试题库 >

如何在运行时实例化Spring托管的bean?

呼延渝
2023-03-14
问题内容

我坚持了从纯Java到Spring的简单重构。应用程序具有一个“容器”对象,该对象在运行时实例化其部分。让我用代码解释一下:

public class Container {
    private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();

    public void load() {
        // repeated several times depending on external data/environment
        RuntimeBean beanRuntime = createRuntimeBean();
        runtimeBeans.add(beanRuntime);
    }

    public RuntimeBean createRuntimeBean() {
         // should create bean which internally can have some 
         // spring annotations or in other words
         // should be managed by spring
    }
}

基本上,在装入容器时,它要求某个外部系统向他提供有关每个RuntimeBean的数量和配置的信息,然后根据给定的规范创建bean。

问题是:通常在春季时

ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
Container container = (Container) context.getBean("container");

我们的对象已完全配置,并注入了所有依赖项。但就我而言,我必须实例化一些对象,这些对象在执行load()方法后也需要进行依赖注入。我该如何实现?

我正在使用基于Java的配置。我已经尝试过为RuntimeBeans建立工厂:

public class BeanRuntimeFactory {

    @Bean
    public RuntimeBean createRuntimeBean() {
        return new RuntimeBean();
    }
}

期望@Bean在所谓的“精简”模式下工作。http://docs.spring.io/spring/docs/current/javadoc-
api/org/springframework/context/annotation/Bean.html
不幸的是,我发现只做新的RuntimeBean()并没有什么区别。这是一个类似问题的帖子:如何管理FactoryBean
spring创建的bean?

也有http://docs.spring.io/spring/docs/current/javadoc-
api/org/springframework/beans/factory/annotation/Configurable.html,但在我看来,这就像一把锤子。

我还尝试了ApplicationContext.getBean(“ runtimeBean”,args),其中runtimeBean具有“
Prototype”作用域,但是getBean是一个糟糕的解决方案。

Upd1。 更具体地说,我正在尝试重构此类:https :
//github.com/apache/lucene-
solr/blob/trunk/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@参见#load()方法并找到“返回create(cd,false);”

Upd2。
我在春季文档中发现了一个非常有趣的东西,称为“查找方法注入”:http :
//docs.spring.io/spring/docs/current/spring-framework-
reference/html/beans.html#beans-factory-lookup-method
-注射

还有一张有趣的吉拉票https://jira.spring.io/browse/SPR-5192,其中菲尔·韦伯(Phil
Webb)说https://jira.spring.io/browse/SPR-5192?focusedCommentId=86051&page=com.atlassian.jira
.plugin.system.issuetabpanels:comment-
tabpanel#comment-86051应该在此处使用javax.inject.Provider(它使我想起了Guice)。

更新3。 还有http://docs.spring.io/spring/docs/current/javadoc-
api/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.html

更新4。 所有这些“查找”方法的问题在于它们不支持传递任何参数。我也需要传递参数,就像我对applicationContext.getBean(“
runtimeBean”,arg1,arg2)所做的那样。看起来它已经通过https://jira.spring.io/browse/SPR-7431修复了

更新5。 Google
Guice具有一项名为AssistedInject的简洁功能。https://github.com/google/guice/wiki/AssistedInject


问题答案:

看起来我找到了解决方案。当我使用基于Java的配置时,它甚至比您想像的还要简单。xml中的替代方法是lookup-method,但是仅从Spring
4.1.X版本开始,因为它支持将参数传递给方法。

这是一个完整的工作示例:

public class Container {
    private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
    private RuntimeBeanFactory runtimeBeanFactory;

    public void load() {
        // repeated several times depending on external data/environment
        runtimeBeans.add(createRuntimeBean("Some external info1"));
        runtimeBeans.add(createRuntimeBean("Some external info2"));
    }

    public RuntimeBean createRuntimeBean(String info) {
         // should create bean which internally can have some 
         // spring annotations or in other words
         // should be managed by spring
         return runtimeBeanFactory.createRuntimeBean(info)
    }

    public void setRuntimeBeanFactory(RuntimeBeanFactory runtimeBeanFactory) {
        this.runtimeBeanFactory = runtimeBeanFactory
    }
}

public interface RuntimeBeanFactory {
    RuntimeBean createRuntimeBean(String info);
}

//and finally
@Configuration
public class ApplicationConfiguration {

    @Bean
    Container container() {
        Container container = new Container(beanToInject());
        container.setBeanRuntimeFactory(runtimeBeanFactory());
        return container;
    }

    // LOOK HOW IT IS SIMPLE IN THE JAVA CONFIGURATION
    @Bean 
    public BeanRuntimeFactory runtimeBeanFactory() {
        return new BeanRuntimeFactory() {
            public RuntimeBean createRuntimeBean(String beanName) {
                return runtimeBean(beanName);
            }
        };
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    RuntimeBean runtimeBean(String beanName) {
        return new RuntimeBean(beanName);
    }
}

class RuntimeBean {
    @Autowired
    Container container;
}

而已。

感谢大家。



 类似资料:
  • 我坚持从普通Java到Spring的简单重构。应用程序有一个“容器”对象,该对象在运行时实例化其部分。让我用代码解释一下: 基本上,在加载容器期间,要求一些外部系统向他提供关于每个的数量和配置的信息,然后它根据给定的规范创建bean。 问题是:通常当我们在Spring这样做的时候 我们的对象已完全配置,并已注入所有依赖项。但是在我的例子中,我必须实例化一些对象,在我执行load()方法后,这些对象

  • 我使用JSF和托管Beans创建了一个简单的应用程序。从托管bean,我试图实例化一个将数据存储到数据库的spring bean。然而,“@autowired”注释似乎不起作用,因为我得到了一个nullpointerexcpetion。我阅读了关于如何在Spring中使用JSF和托管bean的所有相关主题,但不能解决这个问题。也许有人可以看看下面的代码,给我一个提示? 服务Bean faces.c

  • 问题内容: 因此,标题非常简单。我有一个处理程序类,它实现了spring提供的接口。在这个类中,我将添加多个具有如下bean类设置的bean : 该方法返回的对象。 稍后,我将获取类实现的必需实例。所有这些都很好。当我要删除其中一个实例并在以后没有注册表实例的位置添加新实例时,就会出现问题。谁能帮我找到一种方法吗? 以下是该类的代码- 问题答案: 您可以利用(在此处查找API)动态删除或注册Bea

  • 问题内容: 我创建了一个Spring方面来处理Retry机制。我还创建了一个Retry注释。以下是重试注释的代码以及处理此注释的方面。 要启用注释,我需要实例化RetryInterceptor类。我要确保对于给定的上下文,只有该对象的一个​​实例。如果由于某种原因创建了多个对象,那么我的建议将被应用多次。我如何才能完全确保始终有1个实例? 问题答案: 我找到了一种方法:)引用:超越DI 我在我的根

  • 注意:这个问题可能与Vaadin有关,也可能与Vaadin无关,这取决于是否有“更好的”解决方案来“重置”bean。 背景场景 我正在构建一个用于输入一些值的向导,当这些值完成时,将发送到一个表(使用Vaadin和加载项“Wizards for Vaadin”)。 该加载项没有提供一种方法来重置向导(即返回到步骤1)而不强制调用当前steps(重写)onAdvance()和onBack()方法,这