I wrote a Spring MVC demo for demonstrating this:
Controller:
@Controller
public class HomeController {
private Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping({ "/", "/home" })
public String showHomePage(Map<String, Object> model) {
logger.info("1: " + System.currentTimeMillis());
asyncTest();
logger.info("2: " + System.currentTimeMillis());
return "home";
}
@Async
private void asyncTest(){
try {
logger.info("3: " + System.currentTimeMillis());
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logger.info("4: " + System.currentTimeMillis());
}
}
Application Context configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<mvc:resources mapping="resources/**" location="/resources/" />
<mvc:annotation-driven />
<bean id="executorService" class="java.util.concurrent.Executors"
factory-method="newFixedThreadPool">
<constructor-arg value="10" />
</bean>
<task:executor id="threadPoolTaskExecutor" pool-size="10" />
<task:annotation-driven executor="executorService" />
<context:component-scan base-package="com.derek" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
For task configuration, I saw 3 versions of configuration, I tried them all, but the results are no different, version 1 is as shown above,
version 2:
<task:annotation-driven />
version 3:
<task:executor id="WhifExecutor" pool-size="10"/>
<task:annotation-driven executor="WhifExecutor" />
I experimented with these configurations, but the results all are like this:
07:49:41.962 [http-bio-8080-exec-3] INFO com.derek.demo.mvc.HomeController - 1: 1367711381956
07:49:41.966 [http-bio-8080-exec-3] INFO com.derek.demo.mvc.HomeController - 3: 1367711381966
07:49:43.966 [http-bio-8080-exec-3] INFO com.derek.demo.mvc.HomeController - 4: 1367711383966
07:49:43.966 [http-bio-8080-exec-3] INFO com.derek.demo.mvc.HomeController - 2: 1367711383966
Frustrated! I see no asynchronous behavior here. Why?
At last, I got the answer on http://stackoverflow.com/questions/5300833/sending-email-with-spring-in-a-new-thread-issue
There are some limitations you need to pay respect to:
The annotated method must belong to a spring bean;
The invocation of the annotated method must be executed from a different Spring Bean (if you are using standard Spring AOP).
Thereby, I restructured my code as this:
@Controller
public class HomeController {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private AsyncService asyncService;
@RequestMapping({ "/", "/home" })
public String showHomePage(Map<String, Object> model) {
logger.info("1: " + System.currentTimeMillis());
asyncService.asyncTest();
logger.info("2: " + System.currentTimeMillis());
return "home";
}
}
@Service
public class AsyncService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Async
public void asyncTest() {
try {
logger.info("3: " + System.currentTimeMillis());
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logger.info("4: " + System.currentTimeMillis());
}
}
18:17:34.958 [http-bio-8080-exec-10] INFO com.derek.demo.mvc.HomeController - 1: 1367749054953
18:17:34.967 [http-bio-8080-exec-10] INFO com.derek.demo.mvc.HomeController - 2: 1367749054967
18:17:34.995 [pool-4-thread-1] INFO com.derek.demo.mvc.AsyncService - 3: 1367749054995
18:17:37.002 [pool-4-thread-1] INFO com.derek.demo.mvc.AsyncService - 4: 1367749057002