如何在运行时实例化 Spring 管理的 bean? [英] How to instantiate Spring managed beans at runtime?

查看:28
本文介绍了如何在运行时实例化 Spring 管理的 bean?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我坚持从普通 Java 到 Spring 的简单重构.应用程序有一个容器"在运行时实例化其部分的对象.我用代码解释一下:

I stuck with a simple refactoring from plain Java to Spring. Application has a "Container" object which instantiates its parts at runtime. Let me explain with the code:

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.

Basically, during load container asks some external system to provide him information about number and configuration of each RuntimeBean and then it create beans according to given spec.

问题是:通常我们在Spring做的时候

The problem is: usually when we do in Spring

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

我们的对象已完全配置并注入了所有依赖项.但就我而言,我必须在执行 load() 方法后实例化一些也需要依赖注入的对象.
我怎样才能做到这一点?

our object is fully configured and have all dependencies injected. But in my case I have to instantiate some objects which also needs dependency injection after I execute load() method.
How can I achieve that?

我使用的是基于 Java 的配置.我已经尝试为 RuntimeBeans 创建一个工厂:

I am using a Java-based config. I already tried making a factory for 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 不幸的是,我发现简单地执行 new RuntimeBean() 没有区别;这是一个有类似问题的帖子:How to get beans created由 FactoryBean spring 管理?

Expecting @Bean to work in so called 'lite' mode. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html Unfortunately, I found no difference with simply doing new RuntimeBean(); Here is a post with a similar issue: How to get beans created by FactoryBean spring managed?

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

There is also http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Configurable.html but it looks like a hammer in my case.

我还尝试了 ApplicationContext.getBean("runtimeBean", args) 其中 runtimeBean 有一个Prototype"范围,但 getBean 是一个糟糕的解决方案.

I also tried ApplicationContext.getBean("runtimeBean", args) where runtimeBean has a "Prototype" scope, but getBean is an awful solution.

更具体地说,我正在尝试重构这个类:https://github.com/apache/lucene-solr/blob/trunk/solr/core/src/java/org/apache/solr/core/CoreContainer.java@see #load() 方法并找到return create(cd, false);"

To be more concrete I am trying to refactor this class: https://github.com/apache/lucene-solr/blob/trunk/solr/core/src/java/org/apache/solr/core/CoreContainer.java @see #load() method and find "return create(cd, false);"

我发现了一个很有趣的东西,叫做查找方法注入";在 spring 文档中:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection

I found quite interesting thing called "lookup method injection" in spring documentation: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection

还有一张有趣的 jira 票 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).

And also an interesting jira ticket https://jira.spring.io/browse/SPR-5192 where Phil Webb says https://jira.spring.io/browse/SPR-5192?focusedCommentId=86051&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-86051 that javax.inject.Provider should be used here (it reminds me Guice).

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

所有这些查找"方法的问题是它们不支持传递任何参数..我还需要像使用 applicationContext.getBean("runtimeBean", arg1, arg2) 一样传递参数.看起来它在某个时候用 https://jira.spring.io/browse/SPR 修复了-7431

The issue with all these 'lookup' methods is they don't support passing any arguments.. I also need to pass arguments as I would do with applicationContext.getBean("runtimeBean", arg1, arg2). Looks like it was fixed at some point with https://jira.spring.io/browse/SPR-7431

Google Guice 有一个简洁的功能,称为 AssistedInject.https://github.com/google/guice/wiki/AssistedInject

Google Guice have a neat feature for it called AssistedInject. https://github.com/google/guice/wiki/AssistedInject

推荐答案

看起来我找到了解决方案.由于我使用的是基于 Java 的配置,因此它比您想象的还要简单.xml 中的另一种方法是查找方法,但仅从 spring 版本 4.1.X 开始,因为它支持将参数传递给方法.

Looks like I found a solution. As I am using java based configuration it is even simpler than you can imagine. Alternative way in xml would be lookup-method, however only from spring version 4.1.X as it supports passing arguments to the method.

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

Here is a complete working example:

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

就是这样.

谢谢大家.

这篇关于如何在运行时实例化 Spring 管理的 bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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