异步调用
1、配置文件 applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
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/task
http://www.springframework.org/schema/task/spring-task-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/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd" default-autowire="byName">
<!-- 任务及线程池 -->
<task:annotation-driven executor="asyncExecutor" />
<task:executor id="asyncExecutor" pool-size="0-60" queue-capacity="10" />
<!-- 其他配置省略···· -->
</bean>
任务执行器配置详细参数说明:
task:executor/@pool-size:可以指定执行线程池的初始大小、最大大小
task:executor/@queue-capacity:等待执行的任务队列的容量
task:executor/@rejection-policy:当等待队列爆了时的策略,分为丢弃、由任务执行器直接运行等方式
<task:executor id="executor" keep-alive="3600" pool-size="100-200" queue-capacity="500" rejection-policy="CALLER_RUNS" />
2、异步方法
@Service("logCollectionService")
public class LogCollectionServiceImpl implements LogCollectionService{
private final static Logger LOGGER = LoggerFactory.getLogger(LogCollectionServiceImpl.class);
@Autowired
private LogCollectionDao logCollectionDao;
/**
* 记录日志 - 批量
* @param list
*/
@Override
@Async
public void logRemember(List<LogInfoDetail> list){
try {
logCollectionDao.insertLogList(list);
LOGGER.info("数据库记录行为日志成功!");
} catch (Exception e) {
LOGGER.error("数据库记录行为日志失败:",e);
}
}
}
3、异步方法调用
@Controller("logCollectionController")
@RequestMapping("/log")
public class LogCollectionController {
@Autowired
private LogCollectionService logCollectionService;
/**
* 用户行为记录
* @throws Exception
*/
@ResponseBody
@RequestMapping(value = "/remember.do", method = RequestMethod.POST)
public void increaseClicksOfCommonAirlinesAjax(HttpServletRequest request) throws Exception {
String jsonString = request.getParameter("param");
List<LogInfoDetail> logData = JsonUtil.toJavaBeanList(jsonString, new TypeReference<List<LogInfoDetail>>() {});
try {
logCollectionService.logRemember(logData);
} catch (Exception e) {
log.error("AsyncError 异步数据库处理用户行为记录失败",e);
}
}
}
注意
(1)@Async 所修饰的函数不要定义为 static 类型,这样异步调用不会生效。
(2)调用方法和异步函数不能在一个 class 中。
异步回调
如果想知道异步函数什么时候执行完,那就需要使用 Future 来返回异步调用的结果。
改造后的代码如下:
@Service("logCollectionService")
public class LogCollectionServiceImpl implements LogCollectionService{
private final static Logger LOGGER = LoggerFactory.getLogger(LogCollectionServiceImpl.class);
@Autowired
private LogCollectionDao logCollectionDao;
/**
* 记录日志 - 批量
* @param list
*/
@Override
@Async
public Future<String> logRemember(List<LogInfoDetail> list){
try {
logCollectionDao.insertLogList(list);
LOGGER.info("数据库记录行为日志成功!");
} catch (Exception e) {
LOGGER.error("数据库记录行为日志失败:",e);
}
return new AsyncResult<>("执行完成");
}
}
调用:
@Controller("logCollectionController")
@RequestMapping("/log")
public class LogCollectionController {
@Autowired
private LogCollectionService logCollectionService;
/**
* 用户行为记录
* @throws Exception
*/
@ResponseBody
@RequestMapping(value = "/remember.do", method = RequestMethod.POST)
public void increaseClicksOfCommonAirlinesAjax(HttpServletRequest request) throws Exception {
String jsonString = request.getParameter("param");
List<LogInfoDetail> logData = JsonUtil.toJavaBeanList(jsonString, new TypeReference<List<LogInfoDetail>>() {
});
try {
Future<String> task = logCollectionService.logRemember(logData);
while(true){
if(task.isDone()){
break;
}
Thread.sleep(500);
}
} catch (Exception e) {
log.error("AsyncError 异步数据库处理用户行为记录失败",e);
}
}
}
总结
异步调用可以让一些和主要逻辑无关的代码异步执行,以提升性能。比如一些日志的代码、发送邮件短信等代码,可以使用异步执行。
参考文章:Spring 3.1 任务调度