🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 一、概述 耗时的任务,不宜同步执行;我们可以用多线程来实现,但Spring提供了更优雅的机制; ## 二、@Async实现 ### **基本用法** 1、在启动类中加上@EnableAsync注解来开启异步任务,或者新建一个专用的异步线程池配置类; 2、新建一个异步任务类; 3、在业务Service(其实任何地方都可以,但建议在这里调用)中,注入该任务类,并执行; 实例: ``` @Configuration @EnableAsync public class RayAsyncExecutorConfig { private int corePoolSize = 8; private int maxPoolSize = 16; private int queueCapacity = 200; private String threadNamePrefix = "AsyncExecutor-"; @Bean("rayExecutor") public Executor rayExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(corePoolSize); executor.setMaxPoolSize(maxPoolSize); executor.setQueueCapacity(queueCapacity); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix(threadNamePrefix); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } } ``` ``` @Component public class RoleNameRefreshTask { @Async("rayExecutor") public Future<String> test() throws InterruptedException { return new AsyncResult<>(DateUtil.getDateStr(100)); } } ``` 调用代码: ![](https://img.kancloud.cn/1f/8b/1f8b6ef51a8b647b5c5a4ea6c79b7812_937x486.png) ### **事务控制** 如果需要在异步任务中启用事务,那么,需要单独新建业务操作类,在该类的公开方法中加入@Transactional注解,否则,无法控制事务;也就是主方法用@Async标注,然后里面调用另外类的事务方法,事务方法用@Transactional标注,即可; 如果方法中同时加这两个注解,则事务不会生效; ``` @Async public void importAction(RayModel model, SysAsynOrder sysAsynOrder) throws Exception { Workbook wb = Base64Util.getWorkbookByBase64(Base64Util.trimHeadFromFront(sysAsynOrder.getImportedFile())); Sheet sheet = wb.getSheetAt(0); candidateCardProcessor.doLogic(sheet, sysAsynOrder); } ``` ``` @Component public class CandidateCardExecutor extends BaseAsynActionTransactionalExecutor { @Autowired private CardInfoCandidateDao cardInfoCandidateDao; @Transactional public void doLogic(Sheet sheet, SysAsynOrder sysAsynOrder) throws Exception { for (int i = 1; i < sheet.getPhysicalNumberOfRows(); i++) { Row row = sheet.getRow(i); CardInfoCandidate candidate = new CardInfoCandidate(); if (!StringUtil.isEmpty(ExcelUtil.getCellValue(row.getCell(0)).toString())) { candidate.setUserCode(ExcelUtil.getCellStringValue(row.getCell(0), true)); candidate.setIccidCode(ExcelUtil.getCellStringValue(row.getCell(1), true)); candidate.setAccessCode(ExcelUtil.getCellStringValue(row.getCell(2), true)); candidate.setCardSource(ExcelUtil.getCellStringValue(row.getCell(3), true)); candidate.setControlType(ExcelUtil.getCellStringValue(row.getCell(4), true)); candidate.setFunctionType(ExcelUtil.getCellStringValue(row.getCell(5), true)); candidate.setGroupTag(ExcelUtil.getCellStringValue(row.getCell(6), true)); candidate.setCardBoardPrice(StringUtil.isEmpty(ExcelUtil.getCellStringValue(row.getCell(7), true)) ? 0 : NumberUtil.getLongValueByNumberObject(ExcelUtil.getCellStringValue(row.getCell(7), true))); candidate.setSilentDays(StringUtil.isEmpty(ExcelUtil.getCellStringValue(row.getCell(8), true)) ? 0 : NumberUtil.getLongValueByNumberObject(ExcelUtil.getCellStringValue(row.getCell(8), true))); candidate.setTestFlowQuota(StringUtil.isEmpty(ExcelUtil.getCellStringValue(row.getCell(9), true)) ? 0 : NumberUtil.getDoubleValueByObject(ExcelUtil.getCellStringValue(row.getCell(9), true))); cardInfoCandidateDao.save(candidate); } } asynOrderExecutor.completeImportOrder(sysAsynOrder, "完成", AsynOrderStatus.EXECUTED_SUCCESS); } } ``` ## 三、注意 与@Transactional事务类似,异步也是基于动态代理技术实现; >[danger] > 1、异步方法不能使用static修饰; > 2、注解的方法必须是`public`方法; > 3、异步类必须使用@Component注解; > 4、调用异步方法的类与异步方法本身的类不能在同一个类中; > 5、返回值只能为void或者Future;