无法在Thread中获取spring服务bean

时间:2017-10-24 11:29:05

标签: java spring multithreading

我有一个Spring Web应用程序,其中有多个Service和DAO类。在正常的crud操作中,一切正常。但是我在线程中注入依赖时面临问题。

在我的应用程序中,我需要创建一个线程并按需执行它。为此,在控制器类中,我正在创建如下的线程。

TestThread testThread = new TestThread();
Thread thread = new Thread(testThread);
thread.start(); 

在我的帖子中,我试图获得如下的依赖。

WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();        
TestService testService = (TestService) context.getBean("myService");

我的服务类如下所示。

@Service("myService")
public class TestServiceImpl implements TestService {
    some methods...
}

但每次我都低于例外。

Exception in thread "Thread-21" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myService' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:685)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1199)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)

2 个答案:

答案 0 :(得分:0)

而是实施自己的Thread我建议您实施Runnable界面。

class MyTask implements Runnable {
    @Override
    public void run() {
         //your logic is here
    }
}

这个课你甚至可以a prototype bean(例如使用@Scope("prototype"))。在这种情况下,每次要求bean注入所有依赖项时,spring都会创建一个MyTask的新实例。任何其他初始化因请求而异,您可以通过setter方法进行。

任务实例完全初始化后,您可以通过多种不同方式运行它。最简单的方法是手动实例化专用Thread

MyTask task = context.getBean("myTask");
//additional initialization
Thread taskRunner = new Thread(task);
taskRunner.start();

但它不符合您的要求

  

在成功返回前一个线程后逐个执行它们

为此,您可以使用Executor服务。您可以使用spring注入它或在控制器内实例化它:

Executor executor = Executors.newFixedThreadPool(1);

然后执行你的任务看起来会像下面这样:

MyTask task = context.getBean("myTask");
//additional initialization
executor.execute(task); //enqueues the task for future execution

如果您在Java 8上运行它,可以使用lambda以避免实现MyTask

executor.execute(() -> {
    // here you have access to all the injected beans of the controller
    // as well as to arguments of the handler method
});

答案 1 :(得分:0)

正如另一个所说,如果你自己实例化一个新线程,它将不属于Spring业务。

您可以在Spring上下文中执行两项操作。首先是声明一个原型组件线程,并在需要时请求它弹出:

@Component
@Scope("prototype")
public class CustomThread extends Thread{

    @Override
    public void run() {
        System.out.println(“Thread is running");
    }

}

由于它是作用域原型,每次你需要它到spring上下文时,每次都会创建一个新实例。

如果您不喜欢这种方法,可以将taskExecutor定义为spring bean,然后提交实现CustomTask接口的自定义Runnable

public class CustomTask implements Runnable {

    @Override
    public void run() {
        System.out.println("CustomTask is running");
    }

}

这可以是任务执行者的配置:

@Bean
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(10);
    executor.setQueueCapacity(25);
    return executor;
}

如果您愿意,可以查看涵盖这些案例的帖子Spring and Java Thread example