繁体   English   中英

Spring - 在运行时注册scoped bean

[英]Spring - register scoped bean at runtime

我正在开发一个基于Spring的应用程序,它注册一个自定义范围“任务” 我们的想法是,当一个新的Task启动时,Spring应该提供任务范围的对象。

该任务在运行时中实例化。 它以Properties对象的形式提供了一些配置。 我想在ApplicationContext注册该对象,但是在任务范围内,以便该范围内的所有bean都可以引用该特定任务的配置。

这是代码中的粗略思想:

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

我无法弄清楚如何在适当范围内的ApplicationContext中注册bean。

谢谢

更新:

这里有一些代码可以更好地解释这个问题。 SomeScopedBean应该使用bean提供的配置做一些事情,看起来像这样:

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

应用程序的想法是它应该有多个MyTask实例以不同的配置运行,每个任务都是自己的范围。 在每个任务的范围内,应该有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);
        // ...
    }
}

如果我接受你的最后评论:

我想要的是在每个范围内(每个MyTask中)有一个SomeScopedBean实例,但每个配置有不同的配置属性(部署框架在实例化每个Task时提供,

特别是within each MyTask ,如果它仅限于MyTask

您可以:

  • SomeScopedBean定义为原型bean
  • 创建一个工厂@Configuration ,它将使用提供的属性配置实例化SomeScopedBean

首先是配置:

@Configuration
public class SomeScopedBeanFactoryConfiguration {

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

}

然后将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);    
    }
}

注意:如果必须在具有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);

在你的情况下,我会注册MyTask Proxy的单例。 代理可以保留所有与范围相关的实例(例如,在Map或ThreadLocal存储中)和调用委托逻辑,以便从Map中更正一个。

更新:实际上你不是自动装配MyTask bean而是代理。 代理包装了所有MyTask方法。 Proxy具有与MyTask相同的接口。 假设您调用ProxyMyTask.do()方法。 代理拦截调用,获取某种范围,例如Tread Scope示例中的当前线程,并从Map(或ThreadLocal存储的Thread Scope)获取MyTask的正确实例。 最后调用找到的MyTask实例的do(0方法)。

更新2:请参阅示例http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html您可以轻松地包装界面。 您确定范围和返回正确实例的逻辑应该在方法中

@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