项目从头到尾自己开发维护,留下笔记备忘。
项目结构如下:
1、在Application启动类中添加@EnableAsync注解,开启异步。
package com.yydd;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
/**
*
* @类名称 Application.java
*/
@SpringBootApplication
@ComponentScan(basePackages = {"com.yydd.**"})
@EnableDubbo
@EnableAsync
@EnableAutoConfiguration
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
2、在Application启动类 同级目录中 添加 config 包,并创建ThreadPoolTaskConfig.java类
添加spring的配置注解 @Configuration和 异步注解@EnableAsync。
添加@Bean注入 并加入线程池的配置。
代码如下:
package com.yydd.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置类
*/
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
private static final int corePoolSize = 10; // 核心线程数(默认线程数)
private static final int maxPoolSize = 50; // 最大线程数
private static final int keepAliveTime = 300; // 允许线程空闲时间(单位:默认为秒)
private static final int queueCapacity = 1000; // 缓冲队列数
private static final String threadNamePrefix = "pay-api-impl-"; // 线程池名前缀
@Bean("threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
3、如何使用,在需要调用的地方,直接注入
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
以下是我写的例子: 不一定非得这么写,需要根据场景自己实现。
threadPoolTaskExecutor.execute(new SaveTradeInfo(transParam,transResponse.toString(),bizInnerTraInfPoDao,transResponse.getCode()));
SaveTradeInfo 用内部类 实现:
private static class SaveTradeInfo implements Runnable {
private static Logger logger = LoggerFactory.getLogger(SaveTradeInfo.class);
Map<String, Object> requestMap;
String responseMap;
BizInnerTraInfPoDao bizInnerTraInfPoDao;
String flag;
public SaveTradeInfo(Map<String, Object> requestMap, String responseMap, BizInnerTraInfPoDao bizInnerTraInfPoDao, String flag) {
this.requestMap = requestMap;
this.responseMap = responseMap;
this.bizInnerTraInfPoDao = bizInnerTraInfPoDao;
this.flag = flag;
}
@Override
public void run() {
try {
BizInnerTraInfPo bizInnerTraInfPo = new BizInnerTraInfPo();
logger.info("++++++++++++++++开始保存交易记录信息");
bizInnerTraInfPo.setChannelId((String) requestMap.get("channelId"));//TODO 渠道号
bizInnerTraInfPo.setClientid((String) requestMap.get("clientID"));
bizInnerTraInfPo.setSubaccno((String) requestMap.get("payAccNo"));
bizInnerTraInfPo.setSubaccnm((String) requestMap.get("payAccNm"));
bizInnerTraInfPo.setTranamt(requestMap.get("tranAmt").toString());//已和平台约定,金额类必须不为空且大于0
bizInnerTraInfPo.setTrantime(new Date());
bizInnerTraInfPo.setTrantype((String) requestMap.get("tranType"));
if("TX".equals(requestMap.get("tranType"))){
bizInnerTraInfPo.setSubaccno((String) requestMap.get("accountNo"));
bizInnerTraInfPo.setSubaccnm((String) requestMap.get("accountNm"));
}
//根据类型区分目标方账户code和name
if ("BR".equals(requestMap.get("tranType"))) {
bizInnerTraInfPo.setOppaccno((String) requestMap.get("payAccNo"));
bizInnerTraInfPo.setOppaccnm((String) requestMap.get("payAccNm"));
} else {
bizInnerTraInfPo.setOppaccno((String) requestMap.get("recvAccNo"));
bizInnerTraInfPo.setOppaccnm((String) requestMap.get("recvAccNm"));
}
bizInnerTraInfPo.setRemark((String) requestMap.get("memo"));
bizInnerTraInfPo.setBnkCd((String) requestMap.get("bnkCd"));
bizInnerTraInfPo.setRequestparam(requestMap.toString());
bizInnerTraInfPo.setResponseparam(responseMap);
bizInnerTraInfPo.setCreateTime(new Date());
bizInnerTraInfPo.setExpdId(flag);
int result = bizInnerTraInfPoDao.insertSelective(bizInnerTraInfPo);
logger.info("+++++++++++++++++++++++保存记录成功");
} catch (Exception e) {
logger.error("-----------------------------任务{}存记录失败:{}", (String) requestMap.get("clientID"), e.getMessage());
}
}
}
如果发现异步失效,可从以下几点进行排查:
一、异步方法使用static修饰
二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
三、异步方法不能与被调用的异步方法在同一个类中
四、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解