Autowiring Tasks sent to Spring TaskExecutor

前端 未结 2 1677
情话喂你
情话喂你 2021-02-05 14:30

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         


        
相关标签:
2条回答
  • 2021-02-05 15:07

    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);
        }
    }
    
    0 讨论(0)
  • 2021-02-05 15:21

    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.

    0 讨论(0)
提交回复
热议问题