I faced this issue, while trying to autowire a runnable class and creating different instances of it in different call and keeping it in an array.
xml configuration is :
<bean name="threadName" Class="ABC" scope="prototype" />
In my code, I am trying something like this:
public class ThreadHandler{
@Autowired
private ABC threadName;
//getter
ABC getThreadName(){
return threadName;
}
public void someFunction(){
List<ABC> abc = new ArrayList(ABC>();
for (int i=0;i<SOME_CONST;i++){
ABC tName = getThreadName();
abc.add(tName);
tName.start();
}
}
}
Let ABC
be a class which is Thread/Runnable/Callable
.
In this way, it throws java.lang.IllegalThreadStateException
.
But, it works fine, if I use ABC tName =appContext.getBean("threadName",ABC.class);
Why does it happen?
Don't we get a new instance while trying to get an object from getMethod?
No, you don't get a new object, just by accessing a field that holds a reference to a bean scoped as Prototype. Spring doesn't have any way to replace your instance level reference with a new reference based just on field access. It's set once by the autowiring and then it's just a reference to that one object. If you want it to actually create a new one you need to use getBean as you observed.
You can tell Spring to override your get method and replace it with a 'getBean' using method injection, to get the Spring dependencies out of your bean:
There is much better practice when you need to create Runnable/Callable and inject it into applicationContext it's called look up method:
Let's consider that all Runnable/Callable classes are @Prototype and @Lazy
Now you need to Create Look up method factory:
Now let's implement TaskFactory itself which is abstract class and have one abstract method :
Here comes the magic:
Every time you are calling createTask() method of taskFactory singleton object. you will receive completely new instance of your prototype object.
P.S: don't forget to add
to enable Annotations correctly.
hope it Helps.