I have a MyTask
class which implements Runnable
and there can be many such objects instantiated at any given moment. There are certain properties that I would like to autowire into MyTask
class.
But I think that if I mark MyTask
with @Component
then it will become a spring-managed singleton correct? That's not what I want, I need many independent instances of this class to be run by a TaskExecutor.
So my question(s):
- a) Am I fundamentally wrong in my understanding of
@Component
annotation? Does it NOT makeMyTask
into a spring-managed singleton? - b) Is there some other annotation I should use so that spring detects
@Autowired
and injects the property? - c) Is spring autowiring not meant for non-singleton containers/classes like
MyTask
?
Update # 1 - These don't work:
public class MyTask implements Runnable { // I want this class to be non-singleton
@Autowired
public SomeSpecialSpringConfiguredConnectionClass blah; // this is the singleton bean that should be injected
@Override
public void run() {
// BLAH IS NULL, this shouldn't be NULL, that is not what I want
// which makes sense considering Spring never knew it had to work
// on this class
}
}
@Component
public class MyTask implements Runnable { // I want this class to be non-singleton
@Autowired
public SomeSpecialSpringConfiguredConnectionClass blah; // this is the singleton bean that should be injected
@Override
public void run() {
// this works BUT now MyTask is singleton :(
}
}
@Component
@Scope("prototype")
public class MyTask implements Runnable { // I want this class to be non-singleton
@Autowired
public SomeSpecialSpringConfiguredConnectionClass blah; // this is the singleton bean that should be injected
@Override
public void run() {
// BLAH IS NULL, again ... this shouldn't be NULL, that is not what I want
}
}
Update # 2 - While waiting for some more suggestions on how to do it the easy way, I'm looking into: Using AspectJ to dependency inject domain objects with Spring
as an alternative.
first, beans declared with @Component and picked up by spring component scan will become a spring-managed singleton by default.
I have no idea how you use MyTask, but it is overkilled to use AspectJ in your situation, and it does not make much sense to declare MyTask as a spring-managed bean. another way of doing this will be:
define MyTask as a plain java class and add a constructor to initialize the dependency
blah
autowire blah in where you use
MyTask
, and instantiate a MyTask object every time you want to execute a task as follow:The @Component annotation would allow them for auto detetion while classpath scanning using the context:component scan That is what it does. there is a fine line between @Service and @Component, and in this case it does not affect in anyway.
Spring autowiring can be done for prototype as well as singleton scopes. In case of the prototype scope though the lifecycle callbacks for the destruction of the bean isnt called.
It is explained very well on the Spring documentation page. http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html
I dont see a reason why whatever mentioned by you shouldnt work.
He is a working sample of what i tried to do to explain it better.
This is the starting point of the app.
Here is your myTask class
Two other classes to show how the prototype scope is working
A BeanPostprocessor which will show you how the objects are getting created
your SomeSpringConfig class
When you run this sample, you will notice that the output on the console is
If you notice carefulyy there are 2 objects of myTask with different hashcodes.
If you change the scope of the myTask to "Singleton" here would be the output.
In this case there is one object created for "myTask"
Does this help?
Typically adding @Scope("prototype") should not cause null error for autowired blah bean,you should check how you instantiate MyTask bean. I think the problem is that you manually instantiate MyTask like:
and therefor it goes out of Spring's control that is why its dependency, blah bean, is null , instead of manual instantiation, you need to autowire it and let Spring takes care of its dependencies then blah willnot be null. But then there is another issue. Autowiring a prototype bean, MyTask, whithin another singleton object is wrong. Spring container creates a singleton bean only once, and thus only sets the prototype bean once and this causes the prototype scope not to work.Like below, Myactivity is a singleton which autowires MyTask, I also added a constructor for MyTask to print something once a new instance of MyTask gets created. In below case it only prints once, therefore prototype is not working.
Based on Spring AOP Scoped proxies I changed @Scope("prototype") to @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype") so the scoped proxy injects a new instance of MyTask every time singleton MyActivity bean gets called.
and now the prototype is working fine and this was the result printed in console:
Instead of @Autowire, use @Inject and see the magic. I have the same situation, where in, a Validator class is Java Singleton class and not spring scoped bean. I need to inject a UAA Client spring bean provided by another team. So @Autowire didn't work, but @Inject did work.