摘要:從功能上來說,沒有任何的毛病。解決方案每次接受請求之后,根據(jù)的不同,來執(zhí)行不同的業(yè)務(wù)邏輯。具體實現(xiàn)注解表示是個方法注解。通過的接口可以看到具體的使用方式,類上面使用注解,方法上使用注解,注解中傳入類中定義的名字即可。
業(yè)務(wù)場景
在與倉庫系統(tǒng)的對接過程中,我們使用了阿里巴巴的奇門規(guī)范。該規(guī)范中根據(jù)不同的method參數(shù)來確定不同的業(yè)務(wù),比如:
# 入庫單創(chuàng)建 method=taobao.qimen.entryorder.create # 庫存查詢 method=taobao.qimen.inventory.query # 商品同步接口 method=taobao.qimen.singleitem.synchronize
那么我們在解析的時候,常用的方式就是使用switch或者if來處理,以switch為例,實現(xiàn)代碼如下:
switch (method) { case "taobao.qimen.entryorder.create": return entryorderCreate(); case ""taobao.qimen.inventory.query: return inventoryQuery(); case "taobao.qimen.singleitem.synchronize": return singleitemSyncronize(); default: return ""; }
通過switch,我們根據(jù)不同的method能夠返回不同的執(zhí)行邏輯結(jié)果。從功能上來說,沒有任何的毛病。但是作為一個程序員,如果只是為了完成功能而寫代碼,那這樣的程序員是沒有靈魂的。
問題在奇門api技術(shù)文檔中,大概有50多個不同的業(yè)務(wù)接口method,這也就意味著我們至少要case 50次以上。你覺得一個switch中case 50次合理嗎?答案當(dāng)然是不合理的。
在這了再分享一句話:
任何一個傻瓜都能寫出計算機能理解的程序,而優(yōu)秀的程序員卻能寫出別人能讀得懂的程序?!?Martin Fowler解決方案
每次接受請求之后,根據(jù)method的不同,來執(zhí)行不同的業(yè)務(wù)邏輯。那么我們能不能將請求的method和需要執(zhí)行的業(yè)務(wù)邏輯方法做一個映射,這樣我們根據(jù)method就能直接找到具體的業(yè)務(wù)邏輯處理方法。
那么我們的method怎么和我們的業(yè)務(wù)方法映射綁定呢?解決方法是在每個業(yè)務(wù)方法上面增加一個注解(比如@Name)。那么問題來了,我們什么時候生成這樣的映射關(guān)系呢?
我們可以在容器啟動的時候,就去生成這樣的映射關(guān)系。那么我們怎么知道哪些類包含了具有@Name注解的方法呢?
為了能快速獲取到包含@Name注解方法的類,我們增加一個類注解@MethodHandler,在方法上使用了@Name注解的類上我們加上一個@MethodHandler注解,這樣我們就能快速找到這樣的類。
@Name注解
@Target(ElementType.METHOD) @Documented @Retention(RetentionPolicy.RUNTIME) public @interface Name { String[] value() default {}; }
@Target(ElementType.METHOD)表示@Name是個方法注解。同時里面的value是個數(shù)組,是因為可能存在多個method執(zhí)行相同業(yè)務(wù)邏輯的情況
@MethodHandler注解
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MethodHandler { }
@Target({ElementType.TYPE})表示@MethodHandler是個類或者接口注解,此注解的作用是讓我們能快速找到包含@Name注解的方法。
MethodMappering
public class MethodMapping { //方法注解對應(yīng)的名字 public String[] names; //具體的執(zhí)行方法 public Method method; public MethodMapping(String[] names, Method method) { this.names = names; this.method = method; } }
這個類主要存儲奇門method和具體執(zhí)行的方法的映射
MethodNames
public class MethodNames { public static final String deliveryorder_confirm = "deliveryorder.confirm"; public static final String taobao_qimen_deliveryorder_confirm = "taobao.qimen.deliveryorder.confirm"; public static final String deliveryorder_batchconfirm = "deliveryorder.batchconfirm"; public static final String taobao_qimen_deliveryorder_batchconfirm = "taobao.qimen.deliveryorder.batchconfirm"; public static final String stockchange_report = "stockchange.report"; public static final String taobao_qimen_stockchange_report = "taobao.qimen.stockchange.report"; public static final String stockout_confirm = "stockout.confirm"; public static final String taobao_qimen_stockout_confirm = "taobao.qimen.stockout.confirm"; public static final String entryorder_confirm = "entryorder.confirm"; public static final String taobao_qimen_entryorder_confirm = "taobao.qimen.entryorder.confirm"; public static final String itemlack_report = "itemlack.report"; public static final String taobao_qimen_itemlack_report = "taobao.qimen.itemlack.report"; public static final String orderprocess_report = "orderprocess.report"; public static final String taobao_qimen_orderprocess_report = "taobao.qimen.orderprocess.report"; public static final String returnorder_confirm = "returnorder.confirm"; public static final String taobao_qimen_returnorder_confirm = "taobao.qimen.returnorder.confirm"; public static final String returnapply_report = "returnapply.report"; public static final String taobao_qimen_returnapply_report = "taobao.qimen.returnapply.report"; public static final String qimen_taobao_qianniu_cloudkefu_address_self_modify = "qimen.taobao.qianniu.cloudkefu.address.self.modify"; }
MethodNames類主要記錄了奇門中所有的method(此處只展示部分)
注解解析和檢查類DetectMethodAnnotation
@Component public class DetectMethodAnnotation extends AbstractReturner implements ApplicationContextAware, InitializingBean { private ApplicationContext applicationContext; //存儲類-方法 private HashMap> classMethodMap = new HashMap<>(); /** * 初始化容器后解析所有包含MethodHandler注解的類中包含Name注解的方法 * * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { //獲取包含注解MethodHandler的類 Map methodHandlerMap = applicationContext.getBeansWithAnnotation(MethodHandler.class); methodHandlerMap.forEach((k, v) -> { Class> clazz = v.getClass(); Method[] methods = clazz.getDeclaredMethods();//獲取所有的方法 List methodMappings = new ArrayList<>(); for (Method method : methods) { //只解析@Name注解的,并且返回值為Returner的方法,方便對結(jié)果進行解析 if (method.isAnnotationPresent(Name.class) && (method.getReturnType() == Returner.class)) { Name nameAnnotation = method.getAnnotation(Name.class); methodMappings.add(new MethodMapping(nameAnnotation.value(), method)); } } if (!methodMappings.isEmpty()) { classMethodMap.put(clazz.getName(), methodMappings); } }); } /** * 執(zhí)行 * * @param name * @return */ public Returner execute(String name, Object... parameters) throws Exception { if (!classMethodMap.containsKey(this.getClass().getName())) { return fail("類[" + this.getClass().getName() + "]未使用注解@MethodHandler注冊或未發(fā)現(xiàn)任何使用@Name注解的非繼承方法"); } List methodMappings = classMethodMap.get(this.getClass().getName()); for (MethodMapping methodMapping : methodMappings) { String[] names = methodMapping.names; if (Arrays.asList(names).contains(name)) { return (Returner) methodMapping.method.invoke(this, parameters); } } return fail("未發(fā)現(xiàn)使用注解 @Name("" + name + "") 為的方法"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
DetectMethodAnnotation的作用如下:
實現(xiàn)ApplicationContextAware接口,這樣能獲取到上下文對象ApplicationContext
實現(xiàn)InitializingBean接口的afterPropertiesSet()方法,此方法在容器啟動之后只執(zhí)行一次,在此方法中可以解析所有的@Name注解
解析的數(shù)據(jù)存放在classMethodMap中,classMethodMap的數(shù)據(jù)結(jié)構(gòu)Hash<類名,List
提供一個方法execute,外部只需要傳遞method和業(yè)務(wù)邏輯方法的參數(shù)即可。
QimenController
@Controller @MethodHandler public class QimenController extends DetectMethodAnnotation { @Name({MethodNames.deliveryorder_confirm, MethodNames.taobao_qimen_deliveryorder_confirm}) public ReturnerdeliveryorderConfirm(String deliveryOrderCode) { logger.info("execute deliveryorderConfirm method with value " + deliveryOrderCode); return success(""); } @Name(MethodNames.stockchange_report) public Returner stockchangeReport() { return success(""); } }
通過QimenController的接口可以看到具體的使用方式,類上面使用@MethodHandler注解,方法上使用@Name注解,@Name注解中傳入MethodNames類中定義的名字即可。
測試
public class Run { public static final Logger logger = LoggerFactory.getLogger(Run.class); public static void main(String[] args) throws Exception { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Run.class); QimenController qimenController = applicationContext.getBean(QimenController.class); Returnerexecute = qimenController.execute(MethodNames.deliveryorder_confirm, "T123456789"); logger.info("deliveryorder_confirm:{}", execute); logger.info("stockchange_report:{}", qimenController.execute(MethodNames.stockchange_report)); applicationContext.close(); } }
執(zhí)行結(jié)果如下
[main] INFO solution.swithCase.QimenController - [18] - execute deliveryorderConfirm method with value T123456789 [main] INFO solution.swithCase.Run - [29] - deliveryorder_confirm:Returner(code=0, desc=null, body=) [main] INFO solution.swithCase.Run - [30] - stockchange_report:Returner(code=0, desc=null, body=)
Returner對象
@Data public class Returnerimplements Serializable { private String code; private String desc; private T body; }
此對象主要為了統(tǒng)一返回值,方便解析
總結(jié)首先要先明白解決方案思路才能理解代碼,其實就是把類-method-業(yè)務(wù)邏輯做一個映射,這樣就能直接通過接口中傳遞的method來找到具體的業(yè)務(wù)邏輯代碼。如果有不明白的地方可以在下面留言。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75268.html
摘要:結(jié)構(gòu)型模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。行為型模式模版方法模式命令模式迭代器模式觀察者模式中介者模式備忘錄模式解釋器模式模式狀態(tài)模式策略模式職責(zé)鏈模式責(zé)任鏈模式訪問者模式。 主要版本 更新時間 備注 v1.0 2015-08-01 首次發(fā)布 v1.1 2018-03-12 增加新技術(shù)知識、完善知識體系 v2.0 2019-02-19 結(jié)構(gòu)...
摘要:下一代服務(wù)端開發(fā)下一代服務(wù)端開發(fā)第部門快速開始第章快速開始環(huán)境準(zhǔn)備,,快速上手實現(xiàn)一個第章企業(yè)級服務(wù)開發(fā)從到語言的缺點發(fā)展歷程的缺點為什么是產(chǎn)生的背景解決了哪些問題為什么是的發(fā)展歷程容器的配置地獄是什么從到下一代企業(yè)級服務(wù)開發(fā)在移動開發(fā)領(lǐng)域 《 Kotlin + Spring Boot : 下一代 Java 服務(wù)端開發(fā) 》 Kotlin + Spring Boot : 下一代 Java...
摘要:從使用到原理學(xué)習(xí)線程池關(guān)于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實現(xiàn)在軟件開發(fā)中,分散于應(yīng)用中多出的功能被稱為橫切關(guān)注點如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過的點點滴滴,依然清楚的記得當(dāng)初愛情萌芽的模樣…… Java 進階面試問題列表 -...
摘要:使用的好處知乎的回答不用自己組裝,拿來就用。統(tǒng)一配置,便于修改。 前言 只有光頭才能變強 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡單啦 單例模式你會幾種寫法? 工廠模式理解了沒有? 在刷Spring書籍的時候花了點時間去學(xué)習(xí)了單例模式和工廠模式,總的來說還是非常值得的! 本來想的是刷完《Spring 實戰(zhàn) (第4版)》和《精通Spring4.x 企業(yè)應(yīng)用開發(fā)實戰(zhàn)》...
閱讀 2831·2021-09-28 09:45
閱讀 1507·2021-09-26 10:13
閱讀 897·2021-09-04 16:45
閱讀 3661·2021-08-18 10:21
閱讀 1084·2019-08-29 15:07
閱讀 2633·2019-08-29 14:10
閱讀 3147·2019-08-29 13:02
閱讀 2459·2019-08-29 12:31