java 自动装配任务发送到 Spring TaskExecutor

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16094452/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 21:53:37  来源:igfitidea点击:

Autowiring Tasks sent to Spring TaskExecutor

javaspring

提问by Brian DiCasa

How can you have a class that implements Runnable and submitted to springs TaskExecutor autowired?

你怎么能有一个实现 Runnable 并提交给 springs TaskExecutor 自动装配的类?

For example, I have a Task:

例如,我有一个任务:

public class MyTask implements Runnable {

    @Autowired private MyRepository myRepository;

    @Override
    public void run() {
        myRepository.doSomething();
    }
}

And a service that sends a task to the spring TaskExecutor:

还有一个向 spring TaskExecutor 发送任务的服务:

@Service
public class MyService {

    @Autowired private TaskExecutor taskExecutor;

    public void someMethod() {

        MyTask myTask = new MyTask();
        taskExecutor.execute(myTask);

    }

}

I know the fields aren't being autowired because MyTask is getting instantiated using new MyTask(). However, how do I get around this? Should I be getting access to Spring's ApplicationContext and create the bean through it? How would you do this in a web application environment?

我知道这些字段没有被自动装配,因为 MyTask 正在使用 new MyTask() 进行实例化。但是,我该如何解决这个问题?我应该访问 Spring 的 ApplicationContext 并通过它创建 bean 吗?您将如何在 Web 应用程序环境中执行此操作?

Thanks!

谢谢!

采纳答案by jonathan.cone

There are at least two good ways to do this using Spring. First, the @Configurableannotation. 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.

使用 Spring 至少有两种好方法可以做到这一点。首先,@Configurable注解。使用这意味着对 AspectJ 的依赖,但它允许您注入不受 Spring 管理的 bean(即您使用的是 new 运算符)。这将涉及使用@Configurable 注释 MyTask,并在链接中提到的 Spring 配置中添加几行。

@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:

第二种方法涉及使用 Spring 的 ServiceLocatorFactoryBean 特性来创建原型 bean。这在JavaDoc 中得到了最好的解释,但在这种情况下,您可以像任何其他 bean 一样将 TaskFactory 注入 @Service 带注释的类,然后执行如下操作:

@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.

MyTask 已经被注入到您的存储库中,因为您可以在 XML 映射中配置它。我每天都使用这两种方法,但我倾向于使用第二种方法,因为它更容易阅读,并且通过确保开发人员不会做不容易测试的事情来帮助保持开发人员的诚实,坦率地说,它更对不经意的观察者来说很清楚。

回答by Evgeniy Dorofeev

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

或者您可以声明 MyTask 的范围 = "prototype" 并将 MyService 更改为

@Service
public class MyService {
    @Autowired private ApplicationContext ctx;

    public void someMethod() {
        MyTask myTask = ctx.getBean(MyTask.class);
        taskExecutor.execute(myTask);
    }
}