Cleaner way to get new instance of an autowired field that is prototype in nature

 ̄綄美尐妖づ 提交于 2019-11-29 15:47:35

问题


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?


回答1:


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

@Component(value="task")
@Scope(value="prototype")
@Lazy(value=true)
public class Task implements Runnable {

public void run(){
.....
}

}

Now you need to Create Look up method factory:

    <bean id="taskFactory" class="x.y.z.TaskFactory">
<lookup-method name="createTask" bean="task"/>
</bean>

Now let's implement TaskFactory itself which is abstract class and have one abstract method :

@Component(value="taskFactory")
public abstract class TaskFactory {

    public abstract Task createTask();

}

Here comes the magic:

public class ThreadHandler{

@Autowired
private TaskFactory taskFactory;


public void someFunction(){
          Runnable task = taskFactory.createTask();
          taskExecutor.execute(task);
      }
}   

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

<context:annotation-config />
    <context:component-scan base-package="x.y.z"></context:component-scan>

to enable Annotations correctly.

hope it Helps.




回答2:


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:

<bean id="threadHandler" class="com.stackexchange.ThreadHandler">
<lookup-method name="getThreadName" bean="threadName"/>
</bean>


来源:https://stackoverflow.com/questions/10358035/cleaner-way-to-get-new-instance-of-an-autowired-field-that-is-prototype-in-natur

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!