I am working on a Spring-based application which registers a custom scope "task" . The idea is that when a new Task is started, Spring should supply task-scoped objects.
The task is instantiated in the runtime. It is supplied with some configuration in the form of a Properties
object. 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.
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.
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:
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. Within the scope of each task, there should be 1 instance of SomeScopedBean
initialized with the task's configuration.
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,
And especially within each MyTask
and if it is limited to MyTask
.
You can:
SomeScopedBean
as a prototype bean @Configuration
which will instantiate SomeScopedBean
with the provided properties configuration 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
:
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.:
@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. 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.
UPDATE: Actually you autowire not MyTask bean but a Proxy. The proxy wraps all the MyTask methods. Proxy has the same interface as MyTask. Suppose you call ProxyMyTask.do() method. 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. Finally calls the do(0 method of the found MyTask instance.
UPDATE 2: See the example http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html You can easily wrap an interface. 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);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.