Spring 控制器中的 Boot @Async 方法正在同步执行
Spring Boot @Async method in controller is executing synchronously
我的 [basic] Spring 启动应用程序接受来自浏览器的请求,通过 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
class 实现了一个 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" />
所以我认为在主应用程序中编写与此等效的内容 class 会有所帮助:
@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);
}
}
这并没有改变行为。 Ajax 响应在发送请求 10 秒后仍然到达。我错过了什么?
Spring 引导应用程序可以是 downloaded here。安装 Maven 后,项目可以 运行 使用简单的命令:
mvn clean spring-boot:run
注意 由于下面@Dave Syer 提供的答案,问题已解决,他指出我的申请中缺少 @EnableAsync
,即使我上面的代码片段中有一行。
您正在从同一 class 中的另一个方法调用 @Async
方法。除非您为 @EnableAsync
启用 AspectJ 代理模式(当然还提供编织器),否则它将无法工作 (google "proxy self-invocation")。最简单的修复方法是将 @Async
方法放在另一个 @Bean
.
中
我有一个类似的问题,我在正确的 bean 中有注释 @Async 和 @EnableAsync,但该方法仍在同步执行。在我检查日志后,有一条警告说我有不止一个 ThreadPoolTaskExecutor 类型的 bean,其中 none 个叫做 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。
对于所有仍在寻找@Asnyc 中简单解释的所有步骤的人,这里是答案:
这是一个使用@Async 的简单示例。按照以下步骤让@Async 在您的 Spring 启动应用程序中工作:
第 1 步:添加 @EnableAsync 注释并将 TaskExecutor Bean 添加到应用程序 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());
}
}
}
第三步:在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
遵循以下三个步骤:
1 步:
将@EnableAsync 与@configuration 或@SpringBootApplication
一起使用
@EnableAsync public class 应用程序 {
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 放在预期的方法上
T
作为@dave-syer 回答的代码示例:
这是异步工作的:
private void longRunning() {
try {
log.info("wait 3 seconds");
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
log.info("done");
}
@Async
@Override
public void doWork() {
longRunning();
}
但事实并非如此:
@Async
private void longRunning() {
try {
log.info("wait 3 seconds");
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
log.info("done");
}
@Override
public void doWork() {
longRunning();
}
我使用spring-boot main class定义了异步配置。 @EnableAsync
注释使 Spring 能够在后台线程池中 运行 @Async
方法。 class 还通过定义一个新 bean 来自定义 Executor。这里,方法名为taskExecutor()
,因为这是Spring.
搜索到的具体方法名
Spring-Boot-Application.class
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
@Value("${config.threadpool.corepool.size}")
private Integer corePoolSize;
@Value("${config.threadpool.maxpool.size}")
private Integer maxPoolSize;
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
//name of below method should not be changed.
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
//other proeprties to be set here
executor.setThreadNamePrefix("ASYNC-");
executor.initialize();
return executor;
}
}
在实现中,在方法级别使用 @Async
使方法异步。方法需要 public 才能使用 @Async
。此外,@Async
注释方法调用 @Async
方法将不起作用。
下面的示例实现供参考 -
@Async
public void updateData(String userId) throws ApplicationException {
logger.info("Updating details for User with {}", userId);
//your code goes here...
}
配置属性在application.properties
文件
中定义
#Core Pool Size for Async
config.threadpool.corepool.size=100
#Max Pool Size for Async
config.threadpool.maxpool.size=400
pool的定义规则请参考rules-of-a-threadpool-executor
我的 [basic] Spring 启动应用程序接受来自浏览器的请求,通过 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
class 实现了一个 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" />
所以我认为在主应用程序中编写与此等效的内容 class 会有所帮助:
@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);
}
}
这并没有改变行为。 Ajax 响应在发送请求 10 秒后仍然到达。我错过了什么?
Spring 引导应用程序可以是 downloaded here。安装 Maven 后,项目可以 运行 使用简单的命令:
mvn clean spring-boot:run
注意 由于下面@Dave Syer 提供的答案,问题已解决,他指出我的申请中缺少 @EnableAsync
,即使我上面的代码片段中有一行。
您正在从同一 class 中的另一个方法调用 @Async
方法。除非您为 @EnableAsync
启用 AspectJ 代理模式(当然还提供编织器),否则它将无法工作 (google "proxy self-invocation")。最简单的修复方法是将 @Async
方法放在另一个 @Bean
.
我有一个类似的问题,我在正确的 bean 中有注释 @Async 和 @EnableAsync,但该方法仍在同步执行。在我检查日志后,有一条警告说我有不止一个 ThreadPoolTaskExecutor 类型的 bean,其中 none 个叫做 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。
对于所有仍在寻找@Asnyc 中简单解释的所有步骤的人,这里是答案:
这是一个使用@Async 的简单示例。按照以下步骤让@Async 在您的 Spring 启动应用程序中工作:
第 1 步:添加 @EnableAsync 注释并将 TaskExecutor Bean 添加到应用程序 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());
}
}
}
第三步:在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
遵循以下三个步骤:
1 步: 将@EnableAsync 与@configuration 或@SpringBootApplication
一起使用@EnableAsync public class 应用程序 {
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 放在预期的方法上
T
作为@dave-syer 回答的代码示例:
这是异步工作的:
private void longRunning() {
try {
log.info("wait 3 seconds");
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
log.info("done");
}
@Async
@Override
public void doWork() {
longRunning();
}
但事实并非如此:
@Async
private void longRunning() {
try {
log.info("wait 3 seconds");
Thread.sleep(3000);
} catch (InterruptedException e1) {
}
log.info("done");
}
@Override
public void doWork() {
longRunning();
}
我使用spring-boot main class定义了异步配置。 @EnableAsync
注释使 Spring 能够在后台线程池中 运行 @Async
方法。 class 还通过定义一个新 bean 来自定义 Executor。这里,方法名为taskExecutor()
,因为这是Spring.
Spring-Boot-Application.class
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
@Value("${config.threadpool.corepool.size}")
private Integer corePoolSize;
@Value("${config.threadpool.maxpool.size}")
private Integer maxPoolSize;
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
//name of below method should not be changed.
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
//other proeprties to be set here
executor.setThreadNamePrefix("ASYNC-");
executor.initialize();
return executor;
}
}
在实现中,在方法级别使用 @Async
使方法异步。方法需要 public 才能使用 @Async
。此外,@Async
注释方法调用 @Async
方法将不起作用。
下面的示例实现供参考 -
@Async
public void updateData(String userId) throws ApplicationException {
logger.info("Updating details for User with {}", userId);
//your code goes here...
}
配置属性在application.properties
文件
#Core Pool Size for Async
config.threadpool.corepool.size=100
#Max Pool Size for Async
config.threadpool.maxpool.size=400
pool的定义规则请参考rules-of-a-threadpool-executor