Как мне автоматически подключить поток, созданный Spring TaskExecutor?

Согласно документации Spring способ использовать TaskExecutor следующим образом:

import org.springframework.core.task.TaskExecutor;

public class TaskExecutorExample {

  private class MessagePrinterTask implements Runnable {

    private String message;

    public MessagePrinterTask(String message) {
      this.message = message;
    }

    public void run() {
      System.out.println(message);
    }

  }

  private TaskExecutor taskExecutor;

  public TaskExecutorExample(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }

  public void printMessages() {
    for(int i = 0; i < 25; i++) {
      taskExecutor.execute(new MessagePrinterTask("Message" + i));
    }
  }
}

Однако, если MessagePrinterTask имеет автосвязанные зависимости, они не будут настроены Spring, потому что мы создаем экземпляр нашего bean-компонента вне контекста Spring (по крайней мере, я так это понимаю), даже если Spring обеспечит фактическое создание потока. Если MessagePrinterTask должен был иметь автосвязывание зависимостей, как мы можем заставить Spring распознавать их? Я попробовал следующий измененный пример безрезультатно (и да, автосвязывание включено правильно):

import org.springframework.core.task.TaskExecutor;

public class TaskExecutorExample {

  @Component
  private class MessagePrinterTask implements Runnable {

    @Autowired
    private autoWiredDependency;

    public void run() {
      autoWiredDependency.doNotThrowNullPointerExceptionPlease();
    }

  }

  private TaskExecutor taskExecutor;

  public TaskExecutorExample(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }

  public void printMessages() {
    for(int i = 0; i < 25; i++) {
      taskExecutor.execute(new MessagePrinterTask());
    }
  }
}

person Jorge    schedule 02.08.2012    source источник


Ответы (3)


Я думаю, что есть два способа сделать это:

а. Укажите зависимости для задачи - таким образом:

class MessagePrinterTask implements Runnable {
    public MessagePrinterTask(ADependency aDependency){
        this.aDependency = aDependency;
    }


    private ADependency aDependency;

    public void run() {
        aDependency.doNotThrowNullPointerExceptionPlease();
    }
}

И в вашем TaskExectorExample, который может быть синглтоном:

import org.springframework.core.task.TaskExecutor;

public class TaskExecutorExample {

  @Autowired  private ADependency aDependency;

  @Autowired
  public TaskExecutorExample(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }

  public void printMessages() {
    for(int i = 0; i < 25; i++) {
      taskExecutor.execute(new MessagePrinterTask(this.aDependency));
    }
  }
}

б. Используя аннотацию @Configurable в вашем MesasgePrinterTask, это будет внедрять зависимости в MessagePrinterTask, даже если он создается вне контейнера Spring — хотя при использовании @Configurable есть некоторые уловы (требуется AspectJ):

@Configurable
class MessagePrinterTask implements Runnable {
person Biju Kunjummen    schedule 03.08.2012
comment
Спасибо за быстрый ответ Биджу. Предложение а. это то, что я сейчас делаю, но это немного раздражает, так как мне приходится поддерживать конструктор и автопроводные зависимости в классе, который может их не использовать. Я видел предложение б. но я не уверен, что это самый весенний способ выполнить задачу. Спасибо хоть! - person Jorge; 03.08.2012
comment
Сейчас я использую @Configurable, поскольку он превосходит вариант а. Мое приложение также не создает много потоков, поэтому этого достаточно. - person Jorge; 07.08.2012
comment
Другая проблема с a. заключается в том, что если вы используете много сервисов в своей задаче, вы получите длинный список параметров. Кроме того, если вы вложили экземпляры new в свою задачу, вы должны отправить эти параметры также в их соответствующие конструкторы, поскольку @Autowired там тоже не будет работать. - person ACV; 25.09.2020

Вы также можете использовать аннотацию @Async.

public class TaskExecutorExample {

    @Autowired
    private MessagePrinterTask task;

    public void printMessages() {
        for(int i = 0; i < 25; i++) {
            task.printMessage();
        }
    }
}

@Component
public class MessagePrinterTask implements Runnable {

    @Autowired
    private String message;

    @Async
    public void printMessage() {
      System.out.println(message);
    }

}

Любой вызов printMessage() будет выполняться асинхронно с использованием исполнителя по умолчанию, который вы можете настроить, используя следующее в конфигурации Spring xml.

<task:annotation-driven executor="myExecutor"/>
<task:executor id="myExecutor" pool-size="5" />
person Alex    schedule 19.07.2013

Попробуйте этот метод.

@Service
@Scope("prototype")
public invokeClass {

    @Autowired
    private ApplicationContext applicationContext;



    public void methodName(TestRequest input){
        TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();

        taskExecutor.execute(new Runnable() {
            public void run() {

                applicationContext.getBean("testService", TestService.class).execute(input);
            }
        });
    }
}
person Webster Lou    schedule 09.01.2019