SpringBoot頂層接口實(shí)現(xiàn)類注入項(xiàng)目的方法示例
1、背景
在項(xiàng)目中,我們通常會(huì)具有同一特性的業(yè)務(wù)類定義一個(gè)頂層接口,讓業(yè)務(wù)類實(shí)現(xiàn)這個(gè)接口,通過(guò)接口規(guī)范來(lái)管理這些類。我們將這些實(shí)現(xiàn)接口的業(yè)務(wù)類交托給Spring容器接口后,有時(shí)候需要根據(jù)業(yè)務(wù)類型來(lái)選擇動(dòng)態(tài)選擇對(duì)應(yīng)的業(yè)務(wù)類阿里處理業(yè)務(wù)。這個(gè)時(shí)候就獲取到這些業(yè)務(wù)類并進(jìn)行管理,在需要時(shí)取出對(duì)應(yīng)的業(yè)務(wù)類處理業(yè)務(wù)。如何管理就是本期要介紹的內(nèi)容。
以下是我定義的一個(gè)簡(jiǎn)單的頂層接口,它有兩個(gè)方法,一個(gè)是提供類型的getType()方法,一個(gè)是處理業(yè)務(wù)的hanlde()方法。我們的任務(wù)就是對(duì)其實(shí)現(xiàn)類進(jìn)行管理,當(dāng)需要時(shí)可根據(jù)類型獲取對(duì)應(yīng)實(shí)現(xiàn)類。
public interface IBaseHandler { /** * 獲取處理器類型 * @return 處理器類型 */ int getType(); /** * 處理業(yè)務(wù) * @param t 業(yè)務(wù)數(shù)據(jù) * @param <T> 業(yè)務(wù)數(shù)據(jù)類型 */ <T> void handler(T t); }
2、簡(jiǎn)單的管理方法
我們可以通過(guò)使用@Autowired注解將所有實(shí)現(xiàn)了IBaseHandler接口的類注入到項(xiàng)目當(dāng)中,并在需要時(shí)遍歷業(yè)務(wù)類對(duì)象,獲取對(duì)應(yīng)的對(duì)象來(lái)處理業(yè)務(wù)。代碼如下所示:
@Autowired private List<IBaseHandler> handlers; /** * 處理業(yè)務(wù) * @param type 業(yè)務(wù)類型 * @param data 業(yè)務(wù)數(shù)據(jù) * @param <T> 業(yè)務(wù)數(shù)據(jù)類型 */ public <T> void handle(int type, T data) { handlers.stream().filter(handler -> handler.getType() == type).findAny().orElseThrow(() -> { // 獲取不到業(yè)務(wù)類對(duì)象時(shí)打印日志并拋出異常 log.error("Failed to get handler, type:{}", type); throw new NoSuchElementException("No such handler"); }).handler(data); }
3、更好的管理方法
1、簡(jiǎn)單管理方法的弊端
上面的簡(jiǎn)單管理方法用起來(lái)方便,但是有兩個(gè)弊端:
(1)耦合度高,所有需要使用該接口的地方都需要進(jìn)行注入再遍歷的過(guò)程。
(2)性能較差,每次執(zhí)行業(yè)務(wù)之前都需要遍歷一次列表。
2、解決
我們可以使用一個(gè)工具類,提供靜態(tài)方法來(lái)獲取業(yè)務(wù)類。這樣所有需要獲取業(yè)務(wù)類的地方,就都可以通過(guò)該工具類一步獲取到所需的業(yè)務(wù)類。代碼如下:
1、工具類代碼
@Slf4j public class HandlerManager { /** * 按照type映射的處理器map */ private static Map<Integer, IBaseHandler> typeHandlerMap = new HashMap<>(); /** * 按照類型映射的處理器map */ private static Map<Class<IBaseHandler>, IBaseHandler> clazzHandlerMap = new HashMap<>(); /** * 初始化方法,項(xiàng)目啟動(dòng)時(shí)調(diào)用該方法來(lái)初始化map * @param applicationContext spring 上下文對(duì)象 */ public static void init(ApplicationContext applicationContext) { List<IBaseHandler> handlers = new ArrayList<>(); applicationContext.getBeansOfType(IBaseHandler.class).forEach((name, obj) -> handlers.add(obj)); // 為了方便,兩次循環(huán)構(gòu)建map,一次循環(huán)也可以解決,不過(guò)人為定義的handler數(shù)量不多,一次循環(huán)性能提升不大 typeHandlerMap = handlers.stream().collect(Collectors.toMap(IBaseHandler::getType, obj -> obj)); clazzHandlerMap = handlers.stream().collect(Collectors.toMap(obj -> (Class<IBaseHandler>) obj.getClass(), obj -> obj)); } public IBaseHandler getHandlerByType(int type) { return Optional.ofNullable(typeHandlerMap.get(type)).orElseThrow(() -> { // 獲取不到處理器打印日志并拋出異常 log.info("Failed to get handler, type:{}", type); throw new NoSuchElementException("No such handler error"); }); } public IBaseHandler getHandlerByClass(Class<IBaseHandler> clazz) { return Optional.ofNullable(clazzHandlerMap.get(clazz)).orElseThrow(() -> { // 獲取不到處理器打印日志并拋出異常 log.info("Failed to get handler, clazz:{}", clazz); throw new NoSuchElementException("No such handler error"); }); } }
2、調(diào)用工具類的init方法
由于工具類提供的是靜態(tài)方法,因此無(wú)法通過(guò)注入的方式來(lái)獲取到所有的IBaseHanlder,所以需要借助其他可注入IBaseHanlder的類來(lái)初始化管理對(duì)象,以下是方法:
/** * 項(xiàng)目初始化類 * 繼承ApplicationContextAware,實(shí)現(xiàn)setApplicationContext,可獲取ApplicationContext來(lái)獲取上下文 */ @Component public class ApplicationInit implements ApplicationContextAware { @Autowired private List<IBaseHandler> handlers; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 調(diào)用處理器工具類初始化方法 HandlerManager.init(applicationContext); } }
到此這篇關(guān)于SpringBoot頂層接口實(shí)現(xiàn)類注入項(xiàng)目的方法示例的文章就介紹到這了,更多相關(guān)SpringBoot類注入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot通過(guò)Filter實(shí)現(xiàn)整個(gè)項(xiàng)目接口的SQL注入攔截詳解
- Springboot根據(jù)配置文件動(dòng)態(tài)注入接口實(shí)現(xiàn)類詳解
- 使用SpringBoot根據(jù)配置注入接口的不同實(shí)現(xiàn)類(代碼演示)
- springboot接口多實(shí)現(xiàn)類選擇性注入解決方案
- SpringBoot使用@Autowired為多實(shí)現(xiàn)的接口注入依賴
- 使用Springboot根據(jù)配置文件動(dòng)態(tài)注入接口實(shí)現(xiàn)類
- SpringBoot中多個(gè)實(shí)現(xiàn)的接口正確注入的六種方式
相關(guān)文章
關(guān)于mybatis遇到Integer類型的參數(shù)時(shí)動(dòng)態(tài)sql需要注意條件
這篇文章主要介紹了關(guān)于mybatis遇到Integer類型的參數(shù)時(shí)動(dòng)態(tài)sql需要注意條件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java簡(jiǎn)單實(shí)現(xiàn)猜數(shù)字游戲附C語(yǔ)言版本
猜數(shù)字是興起于英國(guó)的益智類小游戲,起源于20世紀(jì)中期,一般由兩個(gè)人或多人玩,也可以由一個(gè)人和電腦玩。游戲規(guī)則為一方出數(shù)字,一方猜,今天我們來(lái)用Java和C語(yǔ)言分別把這個(gè)小游戲?qū)懗鰜?lái)練練手2021-11-11Java中增強(qiáng)for循環(huán)的實(shí)現(xiàn)原理和坑詳解
增強(qiáng)的for循環(huán)是在傳統(tǒng)的for循環(huán)中增加的強(qiáng)大的迭代功能的循環(huán),是在jdk1.5之后提出來(lái)的。下面這篇文章主要給大家介紹了關(guān)于Java中增強(qiáng)for循環(huán)的實(shí)現(xiàn)原理和坑的相關(guān)資料,需要的朋友可以參考下2018-04-04Java String、StringBuffer與StringBuilder的區(qū)別
本文主要介紹Java String、StringBuffer與StringBuilder的區(qū)別的資料,這里整理了相關(guān)資料及詳細(xì)說(shuō)明其作用和利弊點(diǎn),有需要的小伙伴可以參考下2016-09-09springboot中事務(wù)管理@Transactional的注意事項(xiàng)與使用場(chǎng)景
今天小編就為大家分享一篇關(guān)于springboot中事務(wù)管理@Transactional的注意事項(xiàng)與使用場(chǎng)景,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-04-04Java使用Knife4j優(yōu)化Swagger接口文檔的操作步驟
在現(xiàn)代微服務(wù)開(kāi)發(fā)中,接口文檔的質(zhì)量直接影響了前后端協(xié)作效率,Swagger 作為一個(gè)主流的接口文檔工具,雖然功能強(qiáng)大,但其默認(rèn)界面和部分功能在實(shí)際使用中略顯不足,而 Knife4j 的出現(xiàn)為我們提供了一種增強(qiáng)的選擇,本篇文章將詳細(xì)介紹如何在項(xiàng)目中集成和使用 Knife4j2024-12-12SpringMVC框架中使用Filter實(shí)現(xiàn)請(qǐng)求日志打印方式
這篇文章主要介紹了SpringMVC框架中使用Filter實(shí)現(xiàn)請(qǐng)求日志打印方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10UniApp?+?SpringBoot?實(shí)現(xiàn)微信支付和退款功能
這篇文章主要介紹了UniApp?+?SpringBoot?實(shí)現(xiàn)微信支付和退款功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06spring security結(jié)合jwt實(shí)現(xiàn)用戶重復(fù)登錄處理
本文主要介紹了spring security結(jié)合jwt實(shí)現(xiàn)用戶重復(fù)登錄處理,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03