I'm using spring annotations for configuring Controllers(@EnableWebMvc), services(@service and @ComponentScan). In one of my services I have a method annotated with @Async and I also have @EnableAsync added on my config class. When one of MVC controller calls the service method which is annotated with @Async I expect the controller to return immediately without waiting for the service method to complete. By it does not. When I setup the break point in the service method I see that it is in fact running in a seperate thread i.e. the stacktrace does show that it is using SimpleAsyncTaskExecutor as I configured below.
我正在使用spring注释来配置控制器(@EnableWebMvc),服务(@service和@ComponentScan)。在我的一个服务中,我有一个用@Async注释的方法,我在配置类上也添加了@EnableAsync。当其中一个MVC控制器调用使用@Async注释的服务方法时,我希望控制器立即返回,而不必等待服务方法完成。由它没有。当我在服务方法中设置断点时,我发现它实际上是在一个单独的线程中运行,即堆栈跟踪确实显示它正在使用我在下面配置的SimpleAsyncTaskExecutor。
Here is the annotation in my configuration class looks like
这是我的配置类中的注释
@Configuration
@EnableWebMvc
@EnableScheduling
@ComponentScan(basePackages = "com.mypackage")
@EnableAsync
public class WebApplicationConfig extends WebMvcConfigurerAdapter implements AsyncConfigurer {
...
...
@Override
public Executor getAsyncExecutor() {
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("SimpleExecutor-");
executor.setConcurrencyLimit(props.getIntegerProperty(SysProps.EMAIL_SENDER_CONCURRENT_THREAD_LIMIT));
return executor;
}
And here is my MVC controller method looks like
这是我的MVC控制器方法看起来像
@Autowired
private EmailService emailService;
@ResponseStatus(value = HttpStatus.CREATED)
@RequestMapping(value = "/asset/{assetId}/slideshare/email", method = RequestMethod.POST, produces = JSON_UTF8)
@ResponseBody
@ApiResponseObject
public Link createAndEmailSlideShareLink(@PathVariable final String assetId,
@RequestParam(value = "email") final String email,
@RequestParam(value = "message", required = false) final String message,
final HttpServletRequest request) {
Link link = linkService.createLink()
emailService.sendSlideShareAssetEmail(user,link...
return link;
}
And the service method looks like this
服务方法看起来像这样
@Async
public void sendSlideShareAssetEmail(User user, String email, String msg, String link, Asset asset) {
Why doesn't the MVC controller does not return immediately?
为什么MVC控制器没有立即返回?
1 个解决方案
#1
My guess is that your EmailService bean is being included from two different contexts.
我的猜测是你的EmailService bean包含在两个不同的上下文中。
This answer from Ryan Stewart explains the problem/solution in more detail.
Ryan Stewart的答案更详细地解释了问题/解决方案。
Do you have other configurations that are being used? Is there a *-servlet.xml or other servlets defined in your web.xml that might bring your EmailService into the root context?
您是否有其他正在使用的配置?您的web.xml中是否定义了* -servlet.xml或其他servlet,可能会将您的EmailService带入根上下文?
Do you have a ContextLoaderListener or ServletContextListener defined? Perhaps those are picking up your EmailService in addition to the component scan.
您是否定义了ContextLoaderListener或ServletContextListener?除了组件扫描之外,这些可能还会提取您的EmailService。
Including your entire source tree as the component-scan path seems suspicious. Try restricting the paths you use in your component scan to exclude your EmailService and see if its still running executing in a SimpleAsyncTaskExecutor. If it is than you know its being brought in from a different context. Once you find the other context you should be able to exclude it there and add it back to your component-scan or EnableAsync in the other context.
将整个源树包含为组件扫描路径似乎是可疑的。尝试限制在组件扫描中使用的路径以排除您的EmailService,并查看它是否仍在SimpleAsyncTaskExecutor中执行。如果不是你知道它是从不同的环境中引入的。找到其他上下文后,您应该能够将其排除在那里并将其添加回组件扫描或其他上下文中的EnableAsync。
#1
My guess is that your EmailService bean is being included from two different contexts.
我的猜测是你的EmailService bean包含在两个不同的上下文中。
This answer from Ryan Stewart explains the problem/solution in more detail.
Ryan Stewart的答案更详细地解释了问题/解决方案。
Do you have other configurations that are being used? Is there a *-servlet.xml or other servlets defined in your web.xml that might bring your EmailService into the root context?
您是否有其他正在使用的配置?您的web.xml中是否定义了* -servlet.xml或其他servlet,可能会将您的EmailService带入根上下文?
Do you have a ContextLoaderListener or ServletContextListener defined? Perhaps those are picking up your EmailService in addition to the component scan.
您是否定义了ContextLoaderListener或ServletContextListener?除了组件扫描之外,这些可能还会提取您的EmailService。
Including your entire source tree as the component-scan path seems suspicious. Try restricting the paths you use in your component scan to exclude your EmailService and see if its still running executing in a SimpleAsyncTaskExecutor. If it is than you know its being brought in from a different context. Once you find the other context you should be able to exclude it there and add it back to your component-scan or EnableAsync in the other context.
将整个源树包含为组件扫描路径似乎是可疑的。尝试限制在组件扫描中使用的路径以排除您的EmailService,并查看它是否仍在SimpleAsyncTaskExecutor中执行。如果不是你知道它是从不同的环境中引入的。找到其他上下文后,您应该能够将其排除在那里并将其添加回组件扫描或其他上下文中的EnableAsync。