文章目录
- 一,页面环境搭建
- 二,后台接口逻辑实现
- 三,全局线程池对象
-
- [第一步:定义配置属性类 `ThreadPoolConfigProperties`](#第一步:定义配置属性类
ThreadPoolConfigProperties
) - 第二步:启用配置属性绑定
- [第三步:创建线程池 Bean](#第三步:创建线程池 Bean)
- [Spring 如何获取配置](#Spring 如何获取配置)
- 总结
- [第一步:定义配置属性类 `ThreadPoolConfigProperties`](#第一步:定义配置属性类
这一部分是关于商品详情页的内容,商品详情页包含五部分的内容:
- sku基本信息
- sku图片信息
- spu的销售属性
- spu的介绍
- spu的规格参数
由下面几集构成:
- 203-商城业务-商品详情-环境搭建
- 204-商城业务-商品详情-模型抽取
- 205-商城业务-商品详情-规格参数
- 206-商城业务-商品详情-销售属性组合
- 207-商城业务-商品详情-详情页渲染
- 208-商城业务-商品详情-销售属性渲染
- 209-商城业务-商品详情-sku组合切换
- 210-商城业务-商品详情-异步编排优化
一,页面环境搭建
1,上传详情页静态资源到nignx
使用xftp将课程提供的详情页静态资源上传到nginx的html/static/item
目录。
2,拷贝详情页html模板到product模块的templates文件夹下
3,新增ItemController类
在Product模块的web包下,新增ItemController类,在其中添加详情页接口。
cpp
@Controller
public class ItemController {
@Resource
private SkuInfoService skuInfoService;
/**
* 展示当前sku的详情
* @param skuId
* @return
*/
@GetMapping("/{skuId}.html")
public String skuItem(@PathVariable("skuId") Long skuId, Model model) throws ExecutionException, InterruptedException {
return "item";
}
}
二,后台接口逻辑实现
这个接口的实现,逻辑也比较复杂,一定要做好两步:
- 先理解业务需求
- 根据需求设计返回给前端的数据结构。
这两步完成之后,编码水到渠成。
cpp
@Override
public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
SkuItemVo skuItemVo = new SkuItemVo();
CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
// 1、sku基本信息的获取 pms_sku_info
SkuInfoEntity info = this.getById(skuId);
skuItemVo.setInfo(info);
return info;
}, executor);
// thenAcceptAsync 能接收到上一步的结果,但返回值
CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync((res) -> {
//3、获取spu的销售属性组合
List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(res.getSpuId());
skuItemVo.setSaleAttr(saleAttrVos);
}, executor);
CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync((res) -> {
//4、获取spu的介绍 pms_spu_info_desc
SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
skuItemVo.setDesc(spuInfoDescEntity);
}, executor);
CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync((res) -> {
//5、获取spu的规格参数信息
List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
skuItemVo.setGroupAttrs(attrGroupVos);
}, executor);
//2、sku的图片信息 pms_sku_images
CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
List<SkuImagesEntity> imagesEntities = skuImagesService.getImagesBySkuId(skuId);
skuItemVo.setImages(imagesEntities);
}, executor);
//等到所有任务都完成
CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture).get();
return skuItemVo;
}
三,全局线程池对象
在开发详情页时,我们使用了全局线程池,通过SpringBoot的自动配置装配机制:
- ①读取配置文件中的配置,封装为属性Bean
- ②在自动配置类中使用这个Bean对象封装的属性,创建线程池对象
- ③将线程池对象注入到Spring容器中
第一步:定义配置属性类 ThreadPoolConfigProperties
首先,定义了一个配置属性类 ThreadPoolConfigProperties
,用来存储线程池的配置信息。
该类使用了 @ConfigurationProperties
注解来绑定配置文件中的值到类的属性上。
项目启动时,扫描到带注解@ConfigurationProperties
的类时,会创建一个该类的对象,读取配置文件当前相关的配置作为属性值,最后将对象注入到Spring容器中。
java
@ConfigurationProperties(prefix = "gulimall.thread")
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer keepAliveTime;
}
这里指定了前缀 gulimall.thread
,意味着可以通过在配置文件(如 application.yml
或 application.properties
)中添加以下类似的配置项来设置线程池的参数:
yaml
gulimall:
thread:
coreSize: 20
maxSize: 200
keepAliveTime: 10
第二步:启用配置属性绑定
为了让 Spring Boot 自动绑定这些配置,我们需要在配置类上使用 @EnableConfigurationProperties
注解,并指定配置类的类型。
java
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig {
// ...
}
@EnableConfigurationProperties
注解告诉 Spring 容器,当解析配置时应该激活并实例化指定的配置属性类。这意味着当 Spring Boot 启动时,它会查找带有此注解的类,并根据配置文件中的值填充这些类的属性。
第三步:创建线程池 Bean
在配置类 MyThreadConfig
中,我们通过 @Bean
方法创建了一个 ThreadPoolExecutor
实例并返回它。这将允许 Spring 容器管理这个线程池 Bean。
java
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
return new ThreadPoolExecutor(
pool.getCoreSize(),
pool.getMaxSize(),
pool.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
}
当 Spring 容器扫描到这个配置类时,它会执行 @Bean
方法来创建 ThreadPoolExecutor
实例。这里有几个关键点需要注意:
-
注入配置属性 :
ThreadPoolConfigProperties pool
是方法参数,Spring 会自动注入配置好的ThreadPoolConfigProperties
实例。这是因为我们在配置类上使用了@EnableConfigurationProperties
注解。 -
创建线程池 :在
threadPoolExecutor
方法中,我们根据从pool
对象获取的配置值来创建ThreadPoolExecutor
。例如,pool.getCoreSize()
返回核心线程数等。 -
Bean 注入 :通过
@Bean
注解,Spring 容器将负责管理ThreadPoolExecutor
的生命周期。这意味着线程池可以被其他组件注入和使用。
Spring 如何获取配置
在创建 ThreadPoolExecutor
Bean 的过程中,Spring 会通过以下步骤来获取配置:
-
读取配置文件 :当 Spring Boot 启动时,它会读取配置文件中的配置项,并尝试与带有
@ConfigurationProperties
注解的类进行绑定。 -
实例化配置类 :Spring 会实例化
ThreadPoolConfigProperties
类,并使用配置文件中的值填充其属性。 -
注入配置对象 :当
@Bean
方法被调用时,Spring 会自动注入已经实例化并填充好的ThreadPoolConfigProperties
对象,即pool
参数。 -
创建线程池 :最后,
ThreadPoolExecutor
使用从pool
获取的配置值来初始化。
总结
通过上述步骤,可以看到 Spring Boot 是如何自动地配置线程池的。
配置文件中的值通过 @ConfigurationProperties
绑定到了 ThreadPoolConfigProperties
类中.
然后通过 @EnableConfigurationProperties
和 @Bean
方法,Spring 容器能够自动创建并管理线程池 Bean。
这种机制极大地简化了配置过程,使得开发人员可以更加专注于业务逻辑而不是配置细节。