Более чистый способ получить новый экземпляр поля с автоповтором, которое является прототипом в природе

Я столкнулся с этой проблемой, пытаясь выполнить аутроверку класса runnable и создать разные экземпляры его в разных вызовах и сохранить его в массиве.

xml:

<bean name="threadName" Class="ABC" scope="prototype" />

В моем коде я пробую что-то вроде этого:

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();
      }
}   

}

Пусть ABC - класс, который является Thread/Runnable/Callable.

Таким образом, он выбрасывает java.lang.IllegalThreadStateException. Но, он отлично работает, если я использую ABC tName =appContext.getBean("threadName",ABC.class);

Почему это происходит?

Разве мы не получаем новый экземпляр при попытке получить объект из метода getMethod?

Ответ 1

Существует намного лучшая практика, когда вам нужно создать Runnable/Callable и ввести ее в applicationContext, который называется методом поиска:

Предположим, что все классы Runnable/Callable являются @Prototype и @Lazy

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

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

}

Теперь вам нужно создать метод поиска factory:

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

Теперь давайте реализовать сам TaskFactory, который является абстрактным классом и имеет один абстрактный метод:

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

    public abstract Task createTask();

}

Здесь приходит волшебство:

public class ThreadHandler{

@Autowired
private TaskFactory taskFactory;


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

Каждый раз, когда вы вызываете метод createTask() объекта singleton объекта taskFactory. вы получите полностью новый экземпляр вашего объекта-прототипа.

P.S: не забудьте добавить

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

чтобы включить аннотации правильно.

надеюсь, что это поможет.

Ответ 2

Нет, вы не получите новый объект, просто обратившись к полю, содержащему ссылку на bean в качестве прототипа. Spring не имеет никакого способа заменить ссылку на уровень экземпляра новой ссылкой, основанной только на доступе к полю. Он устанавливается один раз автоуведомлением, а затем он просто ссылается на один объект. Если вы хотите, чтобы на самом деле создать новый, вам нужно использовать getBean, как вы заметили.

Вы можете сказать Spring переопределить ваш метод get и заменить его "getBean" с помощью метода injection, чтобы получить зависимости Spring от вашего bean:

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