自动装配任务发送到 Spring TaskExecutor

Posted

技术标签:

【中文标题】自动装配任务发送到 Spring TaskExecutor【英文标题】:Autowiring Tasks sent to Spring TaskExecutor 【发布时间】:2013-04-18 22:56:59 【问题描述】:

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

例如,我有一个任务:

public class MyTask implements Runnable 

    @Autowired private MyRepository myRepository;

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

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

@Service
public class MyService 

    @Autowired private TaskExecutor taskExecutor;

    public void someMethod() 

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

    


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

谢谢!

【问题讨论】:

【参考方案1】:

试试

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

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

@Service
public class MyService 
    @Autowired private ApplicationContext ctx;

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

【讨论】:

是的,这行得通。我希望让自动装配在任务中工作,因为我有很多依赖项并且不想全部传递它们 - 但是,看起来可能没有办法解决它。 @EvgeniyDorofeev 如何将 MyTask 定义为原型? 如果你使用 Spring xml 配置然后添加 scope="prototype" attr 到 MyTask bean 定义【参考方案2】:

至少有两种使用 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);


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

【讨论】:

以上是关于自动装配任务发送到 Spring TaskExecutor的主要内容,如果未能解决你的问题,请参考以下文章

从 Spring 3 升级到 Spring 5 - 现在自动装配错误

编写定时任务中间件笔记

Spring—— 自动装配

从源码中理解Spring Boot自动装配原理

8 -- 深入使用Spring -- 7...4 使用自动装配

spring学习总结——高级装配学习一(处理自动装配的歧义性)