我的[基本] 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
,即使我在上面的代码片段。
答案 0 :(得分:41)
您正在从同一个类中的另一个方法调用@Async
方法。除非您为@EnableAsync
启用AspectJ代理模式(并提供当然的编织器),否则无法工作(google&#34;代理自我调用&#34;)。最简单的解决方法是将@Async
方法放在另一个@Bean
。
答案 1 :(得分:3)
我有一个类似的问题,我在正确的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。
答案 2 :(得分:1)
作为@ dave-syer答案的代码示例:
这异步工作:
var arrayIn = [
{
vendor_uLID: '5e793a0411d2bef2e375cd00',
productVariations: [
{
variationName: 'Colour',
variationOptions: [
{
name: 'Blue',
record_uLID: '6afa239e-ce53-40eb-addc-836d8ecc0051',
},
{
name: 'green',
record_uLID: '66654830-6850-490a-8eaf-9d505e3e4672',
},
],
},
{
variationName: 'Pattern',
variationOptions: [
{
name: 'Bold',
record_uLID: '6afa239e-ce53-40eb-addc-836d8ecc0055',
},
{
name: 'Spotted',
record_uLID: '66654830-6850-490a-8eaf-9d505e3e4671',
}
],
},
],
},
{
vendor_uLID: '5e7bb266071f9601b6ad8f4e',
productVariations: [
{
variationName: 'Colour',
variationOptions: [
{
name: 'Blue',
record_uLID: '6afa239e-ce53-40eb-addc-836d8ecc0051',
},
{
name: 'purple',
record_uLID: '66654830-6850-490a-8eaf-9d505e3e4672',
},
],
},
{
variationName: 'Pattern',
variationOptions: [
{
name: 'Bold',
record_uLID: '6afa239e-ce53-40eb-addc-836d8ecc0055',
},
{
name: 'Spotted',
record_uLID: '66654830-6850-490a-8eaf-9d505e3e4671',
}
],
},
],
}
]
但这不是:
[
{
"variationName": "Colour",
"variationOptions": [
{
"name": "Blue",
"record_uLID": "6afa239e-ce53-40eb-addc-836d8ecc0051",
"linkedVendors": [
"5e793a0411d2bef2e375cd00",
"5e7bb266071f9601b6ad8f4e",
]
},
{
"name": "green",
"record_uLID": "66654830-6850-490a-8eaf-9d505e3e4672",
"linkedVendors": [
"5e793a0411d2bef2e375cd00",
]
},
{
"name": "purple",
"record_uLID": "66654830-6850-490a-8eaf-9d505e3e4675",
"linkedVendors": [
"5e7bb266071f9601b6ad8f4e",
]
}
]
},
{
"variationName": "Pattern",
"variationOptions": [
{
"name": "Bold",
"record_uLID": "6afa239e-ce53-40eb-addc-836d8ecc0055",
"linkedVendors": [
"5e7bb266071f9601b6ad8f4e",
"5e793a0411d2bef2e375cd00"
]
},
{
"name": "Spotted",
"record_uLID": "66654830-6850-490a-8eaf-9d505e3e4671",
"linkedVendors": [
"5e793a0411d2bef2e375cd00",
"5e7bb266071f9601b6ad8f4e"
]
}
]
}]
答案 3 :(得分:1)
我使用spring-boot主类定义异步配置。 @EnableAsync
注释使Spring能够在后台线程池中运行@Async
方法。此类还通过定义新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
以使方法异步。必须公开使用@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
有关如何定义池的规则,请参阅rules-of-a-threadpool-executor
答案 4 :(得分:0)
按照以下三个步骤操作:
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放在预期的方法
上Ť