13

According to Spring's documentation the way to use the TaskExecutor is as follows:

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

However, if MessagePrinterTask has autowired dependencies they will not be configured by Spring because we are instantiating our bean outside of Spring's context (at least that's how I understand it) even though Spring will provide the actual thread creation. If MessagePrinterTask were to have autowired dependencies how do we get Spring to recognize them? I tried the following modified example to no avail (and yes, autowiring is enabled properly):

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());
    }
  }
}
Jorge
  • 1,924
  • 2
  • 14
  • 11

3 Answers3

16

There are two ways I think that you can go about this:

a. Provide the dependencies to the Task - this way:

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


    private ADependency aDependency;

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

And in your TaskExectorExample which can be the singleton:

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

b. Using @Configurable annotation on your MesasgePrinterTask, this will inject in dependencies into MessagePrinterTask even though it is instantiated outside of a Spring Container - there are some catches in using @Configurable though(requires AspectJ):

@Configurable
class MessagePrinterTask implements Runnable {
Biju Kunjummen
  • 49,138
  • 14
  • 112
  • 125
  • Thanks for the quick reply Biju. Suggestion a. is what I am currently doing but it's a bit annoying since I have to maintain a constructor plus autowire dependencies in a class that may not use them. I've seen suggestion b. but I'm not sure if it's the most Spring-way to accomplish the task. Thanks though! – Jorge Aug 03 '12 at 17:25
  • 1
    I am now using @Configurable as it beats out option a. My application doesn't instantiate a lot of threads either so it suffices. – Jorge Aug 06 '12 at 20:04
  • Another problem with `a.` is that if you use many services in your task, you'll end up with a long list of params. Also if you have nested `new` instantiations in your Task, you have to send those params also in their respective constructors as `@Autowired` would not work there either. – ACV Sep 24 '20 at 21:55
4

You can also use the @Async annotation.

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

}

Any call to printMessage() will be executed asynchronously using a default executor, which you can configure using the following in your Spring xml config.

<task:annotation-driven executor="myExecutor"/>
<task:executor id="myExecutor" pool-size="5" />
Alex
  • 228
  • 1
  • 10
0

Try this method.

@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);
            }
        });
    }
}
Webster Lou
  • 51
  • 1
  • 7