我正在开发一个基于Spring的应用程序,它注册了一个自定义范围"任务" 。我们的想法是,当一个新任务启动时,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);
// ...
}
}
答案 0 :(得分:3)
如果我接受你的最后评论:
我想要的是在每个范围内有一个SomeScopedBean实例 (在每个MyTask中),但每个配置有不同的配置 属性(由部署框架提供时 实例化每个任务,
尤其是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);
}
}
注意:如果必须在SomeScopedBean
/ task
范围内的多个bean中注入thread
,则可以将其范围更改为您的线程范围,例如:
@Bean
@Scope("thread")
public SomeScopedBean create(Properties configuration) {
return new SomeScopedBean(configuration);
}
答案 1 :(得分:2)
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);
}