Spring責(zé)任鏈模式使用實例講解
前言
在工作中會存在這種情況某些業(yè)務(wù)場景會對一份數(shù)據(jù)的屬性進(jìn)行多次設(shè)置,這種情況在傳統(tǒng)的代碼風(fēng)格就是在一個方法中對應(yīng)屬性進(jìn)行依次的set這種編碼會在以后的業(yè)務(wù)迭代中造成很大的耦合,代碼復(fù)用程度很低,后期維護(hù)成本會變大,這個時候就可以使用責(zé)任鏈模式對業(yè)務(wù)set這個步驟進(jìn)行拆分做到可插拔式,從而做到減少迭代成本和維護(hù)成本對以后接手項目的同事友好
開始編寫案例
我這里以電商項目中的商品屬性設(shè)置為例productModel
1.開始搭建一個spring boot 項目
<?xml version="1.0" encoding="UTF-8"?> <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.0</modelVersion> <groupId>org.example</groupId> <artifactId>spring-batch</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2.創(chuàng)建對應(yīng)案例數(shù)據(jù)
package com.wym.pojo; import lombok.Data; /** * 商品基礎(chǔ)模型 */ @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; /** * 商品附帶參數(shù) 方便后期設(shè)置參數(shù) */ @Data public class ProductParamModel { private String vendorCode; }
3.創(chuàng)建責(zé)任鏈處理器
創(chuàng)建一個處理接口,子類根據(jù)自己的業(yè)務(wù)特色去實現(xiàn)接口,對數(shù)據(jù)進(jìn)行加工
/** * 商品處理 */ public interface ProductPostProcessor { /** * 商品加工 * @param productModelList 商品 * @param productParamModel 處理參數(shù) */ void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel); }
這里我設(shè)置3個常用的商品處理
/** * 商品品牌設(shè)置 */ @Component @Slf4j @Order(1) //為了后期方便業(yè)務(wù)操作順序編排 public class ProductBrandMappingPostProcessor implements ProductPostProcessor { @Override public void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel) { log.error("進(jìn)入商品品牌設(shè)置"); } }
/** * 商品映射設(shè)置 */ @Component @Slf4j @Order(2) public class ProductCodeMappingPostProcessor implements ProductPostProcessor { @Override public void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel) { log.error("進(jìn)入商品映射設(shè)置"); } }
/** * 商品庫存設(shè)置 */ @Slf4j @Component @Order(3) public class ProductStockNumberPostProcessor implements ProductPostProcessor { @Override public void productDataProcess(List<? extends ProductModel> productModelList, ProductParamModel productParamModel) { log.error("進(jìn)入商品庫存設(shè)置"); } }
這個時候就已經(jīng)創(chuàng)建好了責(zé)任鏈處理器,接下來就是開始業(yè)務(wù)調(diào)用
4.創(chuàng)建mvc調(diào)用
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<ProductModel> */ public List<ProductModel> queryProduct(); }
impl 這里就是核心點如何操作這個責(zé)任鏈 ApplicationListener 這個取獲取容器中的處理器,并排序
@Service @Slf4j public class ProductServerImpl implements ProductServer, ApplicationListener<ContextRefreshedEvent> { private static List<ProductPostProcessor> productPostProcessorList; /** * 處理排序 * * @param contextRefreshedEvent 環(huán) * @return */ private List<ProductPostProcessor> getProductPostProcesser(ContextRefreshedEvent contextRefreshedEvent) { //子容器加載完畢不進(jìn)這個邏輯 if (contextRefreshedEvent.getApplicationContext().getParent() == null) { //監(jiān)聽容器加載完畢 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; } }
進(jìn)行驗證
調(diào)用 http://localhost:8080/test/query 就會在控制臺中打印出
2023-01-09 11:07:42.178 ERROR 25096 --- [nio-8080-exec-2] c.w.p.i.ProductBrandMappingPostProcessor : 進(jìn)入商品品牌設(shè)置
2023-01-09 11:07:42.178 ERROR 25096 --- [nio-8080-exec-2] c.w.p.i.ProductCodeMappingPostProcessor : 進(jìn)入商品映射設(shè)置
2023-01-09 11:07:42.179 ERROR 25096 --- [nio-8080-exec-2] c.w.p.i.ProductStockNumberPostProcessor : 進(jìn)入商品庫存設(shè)置
這樣就做到了業(yè)務(wù)分離對后期的維護(hù)有幫助
到此這篇關(guān)于Spring責(zé)任鏈模式使用實例講解的文章就介紹到這了,更多相關(guān)Spring責(zé)任鏈模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringBoot統(tǒng)一響應(yīng)體解決方案
這篇文章主要介紹了詳解SpringBoot統(tǒng)一響應(yīng)體解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Eclipse使用maven搭建spring mvc圖文教程
這篇文章主要為大家分享了Eclipse使用maven搭建spring mvc圖文教程,感興趣的小伙伴們可以參考一下2016-05-05Java數(shù)據(jù)結(jié)構(gòu)之實現(xiàn)哈希表的分離鏈接法
今天給大家?guī)淼氖顷P(guān)于Java數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識,文章圍繞著Java哈希表的分離鏈接法展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06springboot通過注解、接口創(chuàng)建定時任務(wù)詳解
使用SpringBoot創(chuàng)建定時任務(wù)其實是挺簡單的,這篇文章主要給大家介紹了關(guān)于springboot如何通過注解、接口創(chuàng)建這兩種方法實現(xiàn)定時任務(wù)的相關(guān)資料,需要的朋友可以參考下2021-07-07OpenFeign實現(xiàn)遠(yuǎn)程調(diào)用
這篇文章主要為大家詳細(xì)介紹了OpenFeign實現(xiàn)遠(yuǎn)程調(diào)用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08Java 將PPT幻燈片轉(zhuǎn)為HTML文件的實現(xiàn)思路
本文以Java程序代碼為例展示如何通過格式轉(zhuǎn)換的方式將PPT幻燈片文檔轉(zhuǎn)為HTML文件,本文通過實例代碼圖文相結(jié)合給大家分享實現(xiàn)思路,需要的朋友參考下吧2021-06-06解決SpringBoot集成Eureka導(dǎo)致返回結(jié)果由json變?yōu)閤ml的問題
這篇文章主要介紹了解決SpringBoot集成Eureka導(dǎo)致返回結(jié)果由json變?yōu)閤ml的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07Java里得到00:00:00格式的時分秒的Timestamp
Java里如何得到00:00:00格式的時分秒的Timestamp ,下面是具體的實現(xiàn)代碼,需要的朋友可以參考下。2009-09-09