How can you have a class that implements Runnable and submitted to springs TaskExecutor autowired?
For example, I have a Task:
public class MyTask implem
try
public class MyTask implements Runnable {
private MyRepository myRepository;
public MyTask(MyRepository myRepository) {
this.myRepository = myRepository;
}
@Override
public void run() {
myRepository.doSomething();
}
}
@Service
public class MyService {
@Autowired private TaskExecutor taskExecutor;
@Autowired private MyRepository myRepository;
public void someMethod() {
MyTask myTask = new MyTask(myRepository);
taskExecutor.execute(myTask);
}
}
or you can declare MyTask's scope = "prototype" and change MyService as
@Service
public class MyService {
@Autowired private ApplicationContext ctx;
public void someMethod() {
MyTask myTask = ctx.getBean(MyTask.class);
taskExecutor.execute(myTask);
}
}
There are at least two good ways to do this using Spring. First, the @Configurable annotation. Using this means a dependency on AspectJ, but it will allow you to inject beans that aren't managed by Spring (i.e. you're using the new operator). This would involve annotating MyTask with @Configurable, and adding a couple of lines to your Spring configuration as mentioned in the link.
@Configurable
public class MyTask implements Runnable { ... }
@Service
public class MyService {
@Autowired private TaskExecutor taskExecutor;
public void someMethod() {
// AspectJ would jump in here and inject MyTask transparently
MyTask myTask = new MyTask();
taskExecutor.execute(myTask);
}
}
The second approach would involve using the ServiceLocatorFactoryBean feature of Spring to create prototype beans. This is best explained in the JavaDoc, but in this circumstance you would inject a TaskFactory into your @Service annotated class, just like any other bean and then do something like so:
@Service
public class MyService {
@Autowired private TaskExecutor taskExecutor;
@Autowired private MyRepository myRepository;
@Autowired private TaskFactory taskFactory;
public void someMethod() {
MyTask myTask = taskFactory.getTask("myTask")
taskExecutor.execute(myTask);
}
}
MyTask would already be injected with your repository, as you could configure this in your XML mapping. I use both of these approaches on a daily basis, but I tend to favor the second one as its easier to read and helps keep developers honest by ensuring that they don't do things that aren't easily testable, and frankly, its more clear to the casual observer.