Java 无法在线程中获取spring服务bean

Java 无法在线程中获取spring服务bean,java,spring,multithreading,Java,Spring,Multithreading,我有一个SpringWeb应用程序,其中有多个服务和DAO类。在正常的积垢操作中,一切正常。但在线程中注入依赖项时,我面临这个问题 在我的应用程序中,我需要创建一个线程并按需执行它。为此,我在控制器类中创建了如下线程 TestThread testThread = new TestThread(); Thread thread = new Thread(testThread); thread.start(); WebApplicationContext context = ContextLo

我有一个SpringWeb应用程序,其中有多个服务和DAO类。在正常的积垢操作中,一切正常。但在线程中注入依赖项时,我面临这个问题

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

TestThread testThread = new TestThread();
Thread thread = new Thread(testThread);
thread.start(); 
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();        
TestService testService = (TestService) context.getBean("myService");
在我的线程中,我试图获得如下所示的依赖项

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)

我建议您实现一个
Runnable
接口,而不是实现自己的
线程

class MyTask implements Runnable {
    @Override
    public void run() {
         //your logic is here
    }
}
您甚至可以创建这个类(例如使用
@Scope(“prototype”)
)。在这种情况下,每次请求bean注入所有依赖项时,spring都会创建一个新的
MyTask
实例。任何因请求而异的附加初始化都可以通过setter方法进行

一旦任务实例完全初始化,您就可以以多种不同的方式运行它。其中最简单的方式是手动实例化专用
线程

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

我建议您实现一个
Runnable
接口,而不是实现自己的
线程

class MyTask implements Runnable {
    @Override
    public void run() {
         //your logic is here
    }
}
您甚至可以创建这个类(例如使用
@Scope(“prototype”)
)。在这种情况下,每次请求bean注入所有依赖项时,spring都会创建一个新的
MyTask
实例。任何因请求而异的附加初始化都可以通过setter方法进行

一旦任务实例完全初始化,您就可以以多种不同的方式运行它。其中最简单的方式是手动实例化专用
线程

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

另一种说法是,如果您自己实例化一个新线程,它将退出Spring业务

在Spring上下文中,您可以做两件事。首先,声明一个原型组件线程,并在需要时要求spring:

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

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

}
由于它是范围化的原型,每次您向spring上下文请求它时,每次都会创建一个新实例

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

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业务

在Spring上下文中,您可以做两件事。首先,声明一个原型组件线程,并在需要时要求spring:

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

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

}
由于它是范围化的原型,每次您向spring上下文请求它时,每次都会创建一个新实例

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

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

如果你愿意,你可以看看关于这些情况的文章。

不要自己创建线程,你可以使用@Async。为什么我应该使用@Async而不是创建线程。这是因为Spring对它所处理的一切都进行了检测。如果您自己实例化一个新线程,它就不属于Spring的业务范围。您不能创建一个名为myTestThread的Springbean,它将由Spring正确地、完全地初始化,包括您的线程中的服务吗?如果我需要创建多个可调用线程,并在成功返回以前的线程后逐个执行它们,该怎么办?我能做到吗?…显然“myService”不在您的“当前web应用程序上下文”(可能在另一个(例如root)上下文中)中(实际上)不在您的“当前web应用程序上下文”中!??;)不要创建您自己的线程,您可以使用@Async来代替。为什么我要使用@Async来代替创建线程。这是因为Spring对它所操作的一切都进行了检测。如果您自己实例化一个新线程,它就不属于Spring的业务范围。您不能创建一个名为myTestThread的Springbean,它将由Spring正确地、完全地初始化,包括您的线程中的服务吗?如果我需要创建多个可调用线程,并在成功返回以前的线程后逐个执行它们,该怎么办?我能做到吗?…显然,“myService”不在您的“当前web应用程序上下文”(可能在另一个(例如root)上下文中!)??;)