业务场景:商品详情页数据查询
业务分析
因为查询商品详情的步骤比较多,部分数据需要远程调用,所以在这种步骤多且耗时的场景下可以使用异步的方式去做
例:
普通方式一步一步查询,总耗时=5个步骤耗时相加(0.5s+0.5s+1s+1.5s+1s=总耗时4.5s)
异步的方式,总耗时=最大步骤耗时(1.5s)
但是这里的业务并不能直接全部使用异步的方式去做,因为步骤3,4,5需要步骤1的结果,而步骤2是不需要使用步骤1的结果的,那么怎么才能在保证效率的情况下使用异步操作呢?还有一个核心的点就是如何获取异步操作时的结果呢?
我们已知的获取异步结果可以使用Future进行get()阻塞线程获取结果或者轮询的方式获取结果,虽然Future能获取结果但是效率低耗资源,这里我们使用Future接口的实现类ComletableFuture来实现异步编程
ComletableFuture优点:(1)回调函数获取异步计算结果 (2)可以设计业务的顺序 (3)Api丰富
1. 封装结果设计
@Data
public class SkuItemVo {
private boolean hasStock = true;
//1.sku基本信息:title,price
SkuInfoEntity info;
//2.sku轮播图片
List<SkuImagesEntity> images;
//3.销售版本组合:颜色、版本、内存——黑色;白色;蓝色
List<ItemSaleAttrsVo> saleAttr;
//4.spu的商品介绍(sku共享):销售属性+展示图
SpuInfoDescEntity desc;
//5.规格与包装:所有属性分组下的所有属性
List<SkuItemSaleAttrVo> groupAttrs;
@Data
public static class ItemSaleAttrsVo{
private Long attrId;
private String attrName;
//当前属性有多少种版本:黑色,白色,蓝色
private List<AttrValueWithSkuIdVo> attrValues;
}
@Data
public static class SkuItemSaleAttrVo{
private String groupName;
private List<SpuBaseAttrVo> attrs;
}
@Data
public static class SpuBaseAttrVo{
private String attrName;
private String attrValue;
}
}
2. 自定义线程池
@Configuration
public class MyThreadConfig {
/**
* int corePoolSize, 核心线程数
* int maximumPoolSize,最新线程数
* long keepAliveTime, 空闲线程剩余时间
* TimeUnit unit,时间单位
* BlockingQueue<Runnable> workQueue 阻塞队列
* ThreadFactory threadFactory, 线程工厂
* RejectedExecutionHandler handler 拒绝策略
*/
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool){
return new ThreadPoolExecutor(
pool.getCoreSize(),
pool.getMaxSize(),
pool.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100000),//最多存储10万异步任务
Executors.defaultThreadFactory(),//默认工厂
new ThreadPoolExecutor.AbortPolicy());//抛弃策略
}
}
3. @ConfigurationProperties 自定义属性,并且可以在配置文件中使用
@ConfigurationProperties(prefix = "gulimall.thread")//元数据处理器,配置问题中书写时有提示
@Component//放在容器中
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer KeepAliveTime;
}
application.properties
gulimall.thread.core-size=20
gulimall.thread.max-size=200
gulimall.thread.keep-alive-time=10
4. 异步编排使用
//导入线程池
@Autowired
ThreadPoolExecutor executor;
//返回详情页信息
@Override
public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
SkuItemVo skuItemVo = new SkuItemVo();
/**
* 1.为什么一定要使用自定义的线程池?
* 2.执行策略:
* 1->3,4,5
* 2
* 3.allof()作用
*/
//1.sku基本信息:title,price
CompletableFuture<SkuInfoEntity> infoFture = CompletableFuture.supplyAsync(new Supplier<SkuInfoEntity>() {
@Override
public SkuInfoEntity get() {
SkuInfoEntity info = getById(skuId);
skuItemVo.setInfo(info);
return info;
}
}, executor);
//3.销售版本组合:颜色、版本、内存
CompletableFuture<Void> saleThread = infoFture.thenAcceptAsync(new Consumer<SkuInfoEntity>() {
@Override
public void accept(SkuInfoEntity skuInfoEntity) {
List<SkuItemVo.ItemSaleAttrsVo> saleAttr = skuSaleAttrValueService.getSkuSaleAttrValue(skuInfoEntity.getSpuId());
skuItemVo.setSaleAttr(saleAttr);
}
}, executor);
//4.spu的商品介绍(sku共享):销售属性+展示图
CompletableFuture<Void> descThread = infoFture.thenAcceptAsync(new Consumer<SkuInfoEntity>() {
@Override
public void accept(SkuInfoEntity skuInfoEntity) {
SpuInfoDescEntity desc = spuInfoDescService.getById(skuInfoEntity.getSpuId());
skuItemVo.setDesc(desc);
}
}, executor);
//5.规格与包装:所有属性分组下的所有属性
CompletableFuture<Void> attrThread = infoFture.thenAcceptAsync(new Consumer<SkuInfoEntity>() {
@Override
public void accept(SkuInfoEntity skuInfoEntity) {
Long catalogId = skuInfoEntity.getCatalogId();
List<SkuItemVo.SkuItemSaleAttrVo> groupAttrs = attrGroupService.getAttrGroupWithAttrsBySpuId(skuInfoEntity.getSpuId(), catalogId);
skuItemVo.setGroupAttrs(groupAttrs);
}
}, executor);
//2.sku轮播图片
CompletableFuture<Void> imagesThread = CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
List<SkuImagesEntity> skuImagesEntities = skuImagesService.getImagesBySkuId(skuId);
skuItemVo.setImages(skuImagesEntities);
}
}, executor);
//等待所有任务执行结束
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(infoFture,saleThread, descThread, attrThread, imagesThread);
voidCompletableFuture.get();
return skuItemVo;
}