我的[基本] Spring Boot应用程序接受来自浏览器的请求,通过jQuery.get()
发送,并且应该立即收到响应 - 例如“您的请求已排队”。为此,我写了一个控制器:
@Controller
public class DoSomeWorkController {
@Autowired
private final DoWorkService workService;
@RequestMapping("/doSomeWork")
@ResponseBody
public String doSomeWork() {
workService.doWork(); // time consuming operation
return "Your request has been queued.";
}
}
DoWorkServiceImpl
类实现了DoWorkService
接口,非常简单。它有一种方法来执行耗时的任务。我不需要从此服务调用返回任何内容,因为电子邮件将在工作结束时发送,包括失败或成功方案。所以它实际上看起来像:
@Service
public class DoWorkServiceImpl implements DoWorkService {
@Async("workExecutor")
@Override
public void doWork() {
try {
Thread.sleep(10 * 1000);
System.out.println("completed work, sent email");
}
catch (InterruptedException ie) {
System.err.println(ie.getMessage());
}
}
}
我认为这样可行,但浏览器的Ajax请求在返回响应之前等待了10秒。所以控制器映射方法正在调用同步使用@Async
注释的内部方法,看起来如此。在传统的Spring应用程序中,我通常会将其添加到XML配置中:
<task:annotation-driven />
<task:executor id="workExecutor" pool-size="1" queue-capacity="0" rejection-policy="DISCARD" />
所以我认为在主应用程序类中编写相同的东西会有所帮助:
@SpringBootApplication
@EnableAsync
public class Application {
@Value("${pool.size:1}")
private int poolSize;;
@Value("${queue.capacity:0}")
private int queueCapacity;
@Bean(name="workExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(poolSize);
taskExecutor.setQueueCapacity(queueCapacity);
taskExecutor.afterPropertiesSet();
return taskExecutor;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这并未改变行为。发送请求10秒后,Ajax响应仍然到达。我错过了什么?
Spring Boot应用程序可以是downloaded here。安装Maven后,可以使用简单命令运行项目:
mvn clean spring-boot:run
注意由于下面的@Dave Syer提供的答案,问题得到解决,他指出我在我的应用程序中缺少@EnableAsync
,即使我在上面的代码片段中有这一行。
您正在从同一个类中的另一个方法调用@Async
方法。除非您为@EnableAsync
启用AspectJ代理模式(并且当然提供编织器),否则将无效(谷歌“代理自我调用”)。最简单的解决方法是将@Async
方法放在另一个@Bean
中。
对于那些仍在寻找@Asnyc中所有步骤的人,只需简单的解释,这就是答案:
这是一个使用@Async的简单示例。按照以下步骤使@Async在Spring Boot应用程序中工作:
步骤1:添加@EnableAsync注释并将TaskExecutor Bean添加到Application Class。
例:
@SpringBootApplication
@EnableAsync
public class AsynchronousSpringBootApplication {
private static final Logger logger = LoggerFactory.getLogger(AsynchronousSpringBootApplication.class);
@Bean(name="processExecutor")
public TaskExecutor workExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Async-");
threadPoolTaskExecutor.setCorePoolSize(3);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setQueueCapacity(600);
threadPoolTaskExecutor.afterPropertiesSet();
logger.info("ThreadPoolTaskExecutor set");
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(AsynchronousSpringBootApplication.class,args);
}
}
第2步:添加执行异步过程的方法
@Service
public class ProcessServiceImpl implements ProcessService {
private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
@Async("processExecutor")
@Override
public void process() {
logger.info("Received request to process in ProcessServiceImpl.process()");
try {
Thread.sleep(15 * 1000);
logger.info("Processing complete");
}
catch (InterruptedException ie) {
logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
}
}
}
步骤3:在Controller中添加API以执行异步处理
@Autowired
private ProcessService processService;
@RequestMapping(value = "ping/async", method = RequestMethod.GET)
public ResponseEntity<Map<String, String>> async() {
processService.process();
Map<String, String> response = new HashMap<>();
response.put("message", "Request is under process");
return new ResponseEntity<>(response, HttpStatus.OK);
}
我还在GitHub上用这些步骤编写了一个博客和一个有用的应用程序。请检查:http://softwaredevelopercentral.blogspot.com/2017/07/asynchronous-processing-async-in-spring.html
我有一个类似的问题,我在正确的bean中有@Async和@EnableAsync注释,但仍然是同步执行的方法。检查完日志后,有一个警告说我有多个ThreadPoolTaskExecutor类型的bean,而且没有一个叫做taskExecutor所以......
@Bean(name="taskExecutor")
public ThreadPoolTaskExecutor defaultTaskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
//Thread pool configuration
//...
return pool;
}
有关线程池可用的配置,请参阅http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.html。
按照以下三个步骤:
1步:将@EnableAsync与@configuration或@SpringBootApplication一起使用
@EnableAsync public class Application {
2步骤:
/**
* THIS FOR ASYNCRONOUS PROCESS/METHOD
* @return
*/
@Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("Asynchronous Process-");
executor.initialize();
return executor;
}
3步骤:将@Async放在预期的方法上
Ť