在工作中会存在这种情况某些业务场景会对一份数据的属性进行多次设置,这种情况在传统的代码风格就是在一个方法中对应属性进行依次的set这种编码会在以后的业务迭代中造成很大的耦合,代码复用程度很低,后期维护成本会变大,这个时候就可以使用责任链模式对业务set这个步骤进行拆分做到可插拔式,从而做到减少迭代成本和维护成本对以后接手项目的同事友好
我这里以电商项目中的商品属性设置为例productModel
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>spring-batchartifactId>
<version>1.0-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
package com.wym.pojo;
import lombok.Data;
/**
* 商品基础模型
*/
@Data
public class ProductModel {
private Integer id;
private String productCode;
private String productName;
private String productTitle;
private String productTag;
private String productRegion;
private Integer stockNumber;
private String brandName;
}
package com.wym.pojo;
import lombok.Data;
/**
* 商品附带参数 方便后期设置参数
*/
@Data
public class ProductParamModel {
private String vendorCode;
}
创建一个处理接口,子类根据自己的业务特色去实现接口,对数据进行加工
/**
* 商品处理
*/
public interface ProductPostProcessor {
/**
* 商品加工
* @param productModelList 商品
* @param productParamModel 处理参数
*/
void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel);
}
这里我设置3个常用的商品处理
/**
* 商品品牌设置
*/
@Component
@Slf4j
@Order(1) //为了后期方便业务操作顺序编排
public class ProductBrandMappingPostProcessor implements ProductPostProcessor {
@Override
public void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel) {
log.error("进入商品品牌设置");
}
}
/**
* 商品映射设置
*/
@Component
@Slf4j
@Order(2)
public class ProductCodeMappingPostProcessor implements ProductPostProcessor {
@Override
public void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel) {
log.error("进入商品映射设置");
}
}
/**
* 商品库存设置
*/
@Slf4j
@Component
@Order(3)
public class ProductStockNumberPostProcessor implements ProductPostProcessor {
@Override
public void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel) {
log.error("进入商品库存设置");
}
}
这个时候就已经创建好了责任链处理器,接下来就是开始业务调用
controller
@RequestMapping("/test")
@Slf4j
@RestController
public class ProductController {
@Autowired
private ProductServer productServer;
@GetMapping("/query")
public String queryProduct() {
productServer.queryProduct();
return "成功";
}
}
server
public interface ProductServer {
/**
* 查询商品
* @return List
*/
public List<ProductModel> queryProduct();
}
impl 这里就是核心点如何操作这个责任链 ApplicationListener 这个取获取容器中的处理器,并排序
@Service
@Slf4j
public class ProductServerImpl implements ProductServer, ApplicationListener<ContextRefreshedEvent> {
private static List<ProductPostProcessor> productPostProcessorList;
/**
* 处理排序
*
* @param contextRefreshedEvent 环
* @return
*/
private List<ProductPostProcessor> getProductPostProcesser(ContextRefreshedEvent contextRefreshedEvent) {
//子容器加载完毕不进这个逻辑
if (contextRefreshedEvent.getApplicationContext().getParent() == null) {
//监听容器加载完毕
Map<String, ProductPostProcessor> beansOfType = contextRefreshedEvent.getApplicationContext().getBeansOfType(ProductPostProcessor.class);
log.error("商品后置处理器注入");
List<ProductPostProcessor> postProcessList = new ArrayList<>(beansOfType.values());
postProcessList.sort((a, b) -> {
Order aOrder = AnnotationUtils.findAnnotation(a.getClass(), Order.class);
Order bOrder = AnnotationUtils.findAnnotation(b.getClass(), Order.class);
if (aOrder == null && bOrder == null) {
return 0;
}
if (aOrder == null) {
return 1;
}
if (bOrder == null) {
return -1;
}
return aOrder.value() - bOrder.value();
}
);
return postProcessList;
}
return null;
}
@Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
List<ProductPostProcessor> postProcessor = getProductPostProcesser(contextRefreshedEvent);
if (!CollectionUtils.isEmpty(postProcessor))
{ productPostProcessorList = postProcessor; }
}
@Override public List<ProductModel> queryProduct()
{ ProductModel productModel = new ProductModel(); productModel.setId(0);
productModel.setProductCode("");
productModel.setProductName("");
productModel.setProductTitle("");
productModel.setProductTag("");
productModel.setProductRegion("");
productModel.setStockNumber(0);
productModel.setBrandName("");
ProductParamModel productParamModel = new ProductParamModel(); productParamModel.setVendorCode("1231");
productPostProcessorList.forEach(item -> item.productDataProcess(Arrays.asList(productModel), productParamModel)); return null; }
}
调用 http://localhost:8080/test/query 就会在控制台中打印出
2023-01-09 11:07:42.178 ERROR 25096 --- [nio-8080-exec-2] c.w.p.i.ProductBrandMappingPostProcessor : 进入商品品牌设置
2023-01-09 11:07:42.178 ERROR 25096 --- [nio-8080-exec-2] c.w.p.i.ProductCodeMappingPostProcessor : 进入商品映射设置
2023-01-09 11:07:42.179 ERROR 25096 --- [nio-8080-exec-2] c.w.p.i.ProductStockNumberPostProcessor : 进入商品库存设置
这样就做到了业务分离对后期的维护有帮助