Java @Async在Spring API rest中不工作,带有接口
我正在使用@Async在hibernate数据库中并行存储一些数据。我需要这样做,因为在将信息保存到数据库之前,我需要运行一些需要几分钟的任务。所以我实现了@Async 问题是@Async似乎不起作用。请查找以下代码: 网络配置Java @Async在Spring API rest中不工作,带有接口,java,multithreading,asynchronous,Java,Multithreading,Asynchronous,我正在使用@Async在hibernate数据库中并行存储一些数据。我需要这样做,因为在将信息保存到数据库之前,我需要运行一些需要几分钟的任务。所以我实现了@Async 问题是@Async似乎不起作用。请查找以下代码: 网络配置 @Configuration @EnableAsync @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { } StudentServiceImpl: @Autowired R
@Configuration
@EnableAsync
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
}
StudentServiceImpl:
@Autowired
RunSomeTaskService runSomeTaskService;
@Override
Transactional
public Response saveWithoutWaiting(StudentBO[] students, String username) throws Exception {
...
for (StudentBO student : students) {
....
Future<Response> response = runSomeTaskService.doTasks(student);
//Finish without waiting for doTasks().
}
@Override
Transactional
public Response saveWithWaiting(StudentBO[] students, String username) throws Exception {
...
for (StudentBO student : students) {
....
Future<Response> response = runSomeTaskService.doTasks(student);
//Finish and wait for doTasks().
response.get();
}
public class RunSomeTaskServiceImpl extends CommonService implements RunSomeTaskService{
Student student;
@Override
public Future<Response> doTasks(Student student) {
Response response = new Response();
this.student = student;
//do Task
return new AsyncResult<Response>(response);
}
}
只需使用:
servlet.setAsyncSupported(true);
比如说
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebConfig.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher",
new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
servlet.setAsyncSupported(true); //Servlets were marked as supporting async
// For CORS Pre Filght Request
servlet.setInitParameter("dispatchOptionsRequest", "true");
}
}
好了,我终于成功了 我使用遗嘱执行人的方式如下:
ExecutorService executor = Executors.newFixedThreadPool(students.size());
for (StudentBO student : students) {
executor.submit(() -> extractDataService.doTask(student));
}
其中doTask是一个常规函数,当我不需要它在另一个线程中工作时,我就按原样调用它。当我需要线程时,我会使用上面的代码。WebConfig.java中的@EnableAsync注释可能永远不会被扫描。xml指向spring-context.xml 您可以将web.xml中的DispatcherServlet定义更改为:
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.yourpackage.WebConfig
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
在异步方法中使用如下bean名称
@Async("asyncTaskExecutor")
public Future<Response> doTasks(Student student);
@Async(“asyncTaskExecutor”)
公共未来任务(学生);
这将确保所有任务都在此线程池中执行 更复杂的方法是实现AsyncConfigurer并将AsyncExecutor设置为threadPoolTaskExecutor 下面是示例代码
@Configuration
@EnableAsync(proxyTargetClass=true) //detects @Async annotation
public class AsyncConfig implements AsyncConfigurer {
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // create 10 Threads at the time of initialization
executor.setQueueCapacity(10); // queue capacity
executor.setMaxPoolSize(25); // if queue is full, then it will create new thread and go till 25
executor.setThreadNamePrefix("DEMO-");
executor.initialize();//Set up the ExecutorService.
return executor;
}
@Override
public Executor getAsyncExecutor() {
return threadPoolTaskExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new YOUR_CUSTOM_EXCEPTION_HANDLER();
}
}
上述配置将检测@Async annotation(无论在何处提及)您可以在将来完成,这样您就知道所有任务何时完成了
List<CompletableFuture<T>> futureList = new ArrayList<>();
for(Student student:studentList){
CompletableFuture<T> returnedFuture = CompletableFuture.supplyAsync(() -> doSomething(student),executor).exceptionally(e -> {
log.error("Error occured in print something future",e);
return 0;
});
futureList.add(returnedFuture);
}
Completable.allOf(futureList);
List futureList=new ArrayList();
用于(学生:学生名单){
CompletableFuture returnedFuture=CompletableFuture.supplyAsync(()->doSomething(学生),执行者)。例外情况下(e->{
log.error(“打印时出错”,e);
返回0;
});
futureList.add(返回的Future);
}
可完成。allOf(未来列表);
然后,您可以使用“编写”或“应用”(以获取使用者)管道来完全控制任务管道。安全完成后,您可以关闭执行器
这一行是什么
future.get()
?@ErvinSzilagyi据我所知是强制等待任务完成。。。但是我只是在saveWithWaiting方法中使用它。是的,但是您的代码中没有声明future
,忽略后面的语法错误。请在dotask
和saveWithWaiting
方法中添加带有线程名称的日志,以检查它们是否在同一线程中调用。您确定启动应用程序时会扫描WebConfig
吗?@Async
实际上运行得很好。问题是您没有指定特定的TaskExecutor
来启动线程。异步请求处理(true
)也是异步执行方法的过程。那些是不同的动物。您的RunSomeTaskServiceImpl
的实现也有缺陷,因为它不是线程安全的。DispatcherServlet
旁边的另一个问题是,您是否有正在加载服务的ContextLoaderListener
?因为这会使您的@EnableAsync
变得毫无用处,因为它生活在不同的上下文中。我在WebConfig.java中实现了这一点,并且我得到了一个错误,说我有两个ApplicationContext。。因此,我发现在web.xml中,我必须添加true,以便执行与您建议相同的配置,但它也不起作用。。。我在帖子中添加了web.xml的定义,因此您可以检查这是我得到的错误java.lang.IllegalStateException:未找到唯一的WebApplicationContext:多个DispatcherServlet注册为publishContext=true?这只是一种解决方法。当然,使用您自己的执行器就可以完成这项工作。使用它,您不需要@Async
。创建线程池时,代码是危险的,因为您从未清理过线程池。最终您将耗尽资源和大量空闲线程。如果需要,必须在finally
块中关闭执行器。另外,如果您的系统中只有16个内核可以执行此工作,您希望限制线程的数量,并且不希望创建100个线程。@M.Deinum,并且最终将在所有线程完成后触发?或者,我如何确保在触发finally块之前完成这些操作?关闭操作将在没有更多任务要处理时立即关闭。我添加了spring-config.xml。您能看一下并分享您的意见吗?@Faabass是com.app.controller包中的WebConfig.java还是它的子包?如果不是,则不会扫描它,并且需要将其包添加到基本包中。基本包属性可以有多个逗号分隔的包,如Base package=“x.y.z.service,x.y.z.controller”
。谢谢!我将其添加到基本包中,现在它在@Async中工作,无论如何I0m还有其他问题。请看我的帖子,我强烈建议你提出一个新问题,并将此标记为原始问题的答案。完成!这就是问题所在。。。我在WebConfig之外的同一个包中创建了一个新类,并将该包添加到基本包中,但数据库会话仍不断出错。。。我知道会话是重复的,诸如此类的事情……你能分享堆栈跟踪吗?谢谢,当然!补充。。我对此感到绝望。我正在做的是,我正在做一些处理,然后我正在以并行方式更新数据库中的学生,这使应用程序以异步方式执行方法!我更新了代码以使用CompletableFuture。。但是我在hibernate会话中遇到了错误,我在帖子中添加了stracktrace
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebConfig.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher",
new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
servlet.setAsyncSupported(true); //Servlets were marked as supporting async
// For CORS Pre Filght Request
servlet.setInitParameter("dispatchOptionsRequest", "true");
}
}
ExecutorService executor = Executors.newFixedThreadPool(students.size());
for (StudentBO student : students) {
executor.submit(() -> extractDataService.doTask(student));
}
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
com.yourpackage.WebConfig
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
@Bean
public Executor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("asynctaskpool-");
executor.initialize();
return executor;
}
@Async("asyncTaskExecutor")
public Future<Response> doTasks(Student student);
@Configuration
@EnableAsync(proxyTargetClass=true) //detects @Async annotation
public class AsyncConfig implements AsyncConfigurer {
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // create 10 Threads at the time of initialization
executor.setQueueCapacity(10); // queue capacity
executor.setMaxPoolSize(25); // if queue is full, then it will create new thread and go till 25
executor.setThreadNamePrefix("DEMO-");
executor.initialize();//Set up the ExecutorService.
return executor;
}
@Override
public Executor getAsyncExecutor() {
return threadPoolTaskExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new YOUR_CUSTOM_EXCEPTION_HANDLER();
}
}
List<CompletableFuture<T>> futureList = new ArrayList<>();
for(Student student:studentList){
CompletableFuture<T> returnedFuture = CompletableFuture.supplyAsync(() -> doSomething(student),executor).exceptionally(e -> {
log.error("Error occured in print something future",e);
return 0;
});
futureList.add(returnedFuture);
}
Completable.allOf(futureList);