简体   繁体   English

Spring - 在运行时注册scoped bean

[英]Spring - register scoped bean at runtime

I am working on a Spring-based application which registers a custom scope "task" . 我正在开发一个基于Spring的应用程序,它注册一个自定义范围“任务” The idea is that when a new Task is started, Spring should supply task-scoped objects. 我们的想法是,当一个新的Task启动时,Spring应该提供任务范围的对象。

The task is instantiated in the runtime. 该任务在运行时中实例化。 It is supplied with some configuration in the form of a Properties object. 它以Properties对象的形式提供了一些配置。 I want to register that object with the ApplicationContext but within the task scope so that all beans within that scope can reference the configuration of that particular task. 我想在ApplicationContext注册该对象,但是在任务范围内,以便该范围内的所有bean都可以引用该特定任务的配置。

Here is the rough idea in code: 这是代码中的粗略思想:

public class MyTask extends SourceTask {
    @Override
    public void start(Map<String, String> props) {
        context = ContextProvider.getApplicationContext();
        // Initialize the scope
        ConnectorTaskScope scope = context.getBean(ConnectorTaskScope.class);
        scope.startNewTask();

        // TODO register the props object in the context

        // get an object which requires the properties and work with it
        context.getBean(SomeScopedBean.class);        
    }
}

I can't figure out how can I register a bean in the ApplicationContext that is scoped appropriately. 我无法弄清楚如何在适当范围内的ApplicationContext中注册bean。

Thank you 谢谢

Update: 更新:

Here is some more code to explain the question a bit better. 这里有一些代码可以更好地解释这个问题。 SomeScopedBean should be doing something with the configuration it has bean provided with and looks something like this: SomeScopedBean应该使用bean提供的配置做一些事情,看起来像这样:

public class SomeScopedBean {
    @Autowire
    public SomeScopedBean (Properties configuration) {
        // do some work with the configuration 
    }
}

The idea of the application is that it should have multiple instances of MyTask running with different configuration and each task is its own scope. 应用程序的想法是它应该有多个MyTask实例以不同的配置运行,每个任务都是自己的范围。 Within the scope of each task, there should be 1 instance of SomeScopedBean initialized with the task's configuration. 在每个任务的范围内,应该有1个使用任务配置初始化的SomeScopedBean实例。

public class MyApplication {
    public static void main (String[] args) {
        // ...
        Properties config1 = loadConfiguration1();
        Properties config2 = loadConfiguration2();
        MyTask task1 = new MyTask();
        MyTask task2 = new MyTask();
        task1.start(config1);
        task2.start(config2);
        // ...
    }
}

If I take your last comment: 如果我接受你的最后评论:

What I want is to have 1 instance of SomeScopedBean within each scope (within each MyTask), but each configured with different configuration properties (which are provided by the deployment framework when it instantiates each Task, 我想要的是在每个范围内(每个MyTask中)有一个SomeScopedBean实例,但每个配置有不同的配置属性(部署框架在实例化每个Task时提供,

And especially within each MyTask and if it is limited to MyTask . 特别是within each MyTask ,如果它仅限于MyTask

You can: 您可以:

  • define SomeScopedBean as a prototype bean SomeScopedBean定义为原型bean
  • create a factory @Configuration which will instantiate SomeScopedBean with the provided properties configuration 创建一个工厂@Configuration ,它将使用提供的属性配置实例化SomeScopedBean

First the configuration: 首先是配置:

@Configuration
public class SomeScopedBeanFactoryConfiguration {

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public SomeScopedBean create(Properties configuration) {
        return new SomeScopedBean(configuration);
    }

}

Then autowired the SomeScopedBeanFactoryConfiguration into MyTask and creates SomeScopedBean : 然后将SomeScopedBeanFactoryConfiguration装入MyTask并创建SomeScopedBean

public class MyTask extends SourceTask {

    @Autowired
    private SomeScopedBeanFactoryConfiguration  someScopedBeanFactoryConfiguration;

    @Override
    public void start(Map<String, String> props) {
        SomeScopedBean scopedBean = someScopedBeanFactoryConfiguration.create(props);    
    }
}

Note: if SomeScopedBean must be injected in more than one bean with the task / thread scope, you could change its scope to your thread scope one eg.: 注意:如果必须在具有task / thread范围的多个bean中注入SomeScopedBean ,则可以将其范围更改为线程范围1,例如:

    @Bean
    @Scope("thread")
    public SomeScopedBean create(Properties configuration) {
        return new SomeScopedBean(configuration);
    }
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();

MyTask instance = new MyTask();
beanFactory.autowireBean(instance);
beanFactory.initializeBean(instance, MyTask.class.getCanonicalName());

//for singleton I used
((ConfigurableListableBeanFactory)beanFactory).registerSingleton(MyTask.class.getCanonicalName(), instance);

In your case I would register singleton of MyTask Proxy. 在你的情况下,我会注册MyTask Proxy的单例。 The Proxy can keep all your scope dependent instances (eg in a Map or in ThreadLocal storage) and on call delegate logic to correct one from the Map. 代理可以保留所有与范围相关的实例(例如,在Map或ThreadLocal存储中)和调用委托逻辑,以便从Map中更正一个。

UPDATE: Actually you autowire not MyTask bean but a Proxy. 更新:实际上你不是自动装配MyTask bean而是代理。 The proxy wraps all the MyTask methods. 代理包装了所有MyTask方法。 Proxy has the same interface as MyTask. Proxy具有与MyTask相同的接口。 Suppose you call ProxyMyTask.do() method. 假设您调用ProxyMyTask.do()方法。 The proxy intercepts the call, get somehow scope eg current thread in case of Tread Scope example and get from the Map (or for Thread Scope from ThreadLocal storage) proper instance of MyTask. 代理拦截调用,获取某种范围,例如Tread Scope示例中的当前线程,并从Map(或ThreadLocal存储的Thread Scope)获取MyTask的正确实例。 Finally calls the do(0 method of the found MyTask instance. 最后调用找到的MyTask实例的do(0方法)。

UPDATE 2: See the example http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html You can easily wrap an interface. 更新2:请参阅示例http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html您可以轻松地包装界面。 Your logic to determine scope and return proper instance should be in the method 您确定范围和返回正确实例的逻辑应该在方法中

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    return method.invoke(target, args);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM