我有一个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)
答案 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。