SpringBoot頂層接口實現(xiàn)類注入項目的方法示例
1、背景
在項目中,我們通常會具有同一特性的業(yè)務類定義一個頂層接口,讓業(yè)務類實現(xiàn)這個接口,通過接口規(guī)范來管理這些類。我們將這些實現(xiàn)接口的業(yè)務類交托給Spring容器接口后,有時候需要根據(jù)業(yè)務類型來選擇動態(tài)選擇對應的業(yè)務類阿里處理業(yè)務。這個時候就獲取到這些業(yè)務類并進行管理,在需要時取出對應的業(yè)務類處理業(yè)務。如何管理就是本期要介紹的內(nèi)容。
以下是我定義的一個簡單的頂層接口,它有兩個方法,一個是提供類型的getType()方法,一個是處理業(yè)務的hanlde()方法。我們的任務就是對其實現(xiàn)類進行管理,當需要時可根據(jù)類型獲取對應實現(xiàn)類。
public interface IBaseHandler {
/**
* 獲取處理器類型
* @return 處理器類型
*/
int getType();
/**
* 處理業(yè)務
* @param t 業(yè)務數(shù)據(jù)
* @param <T> 業(yè)務數(shù)據(jù)類型
*/
<T> void handler(T t);
}
2、簡單的管理方法
我們可以通過使用@Autowired注解將所有實現(xiàn)了IBaseHandler接口的類注入到項目當中,并在需要時遍歷業(yè)務類對象,獲取對應的對象來處理業(yè)務。代碼如下所示:
@Autowired
private List<IBaseHandler> handlers;
/**
* 處理業(yè)務
* @param type 業(yè)務類型
* @param data 業(yè)務數(shù)據(jù)
* @param <T> 業(yè)務數(shù)據(jù)類型
*/
public <T> void handle(int type, T data) {
handlers.stream().filter(handler -> handler.getType() == type).findAny().orElseThrow(() -> {
// 獲取不到業(yè)務類對象時打印日志并拋出異常
log.error("Failed to get handler, type:{}", type);
throw new NoSuchElementException("No such handler");
}).handler(data);
}
3、更好的管理方法
1、簡單管理方法的弊端
上面的簡單管理方法用起來方便,但是有兩個弊端:
(1)耦合度高,所有需要使用該接口的地方都需要進行注入再遍歷的過程。
(2)性能較差,每次執(zhí)行業(yè)務之前都需要遍歷一次列表。
2、解決
我們可以使用一個工具類,提供靜態(tài)方法來獲取業(yè)務類。這樣所有需要獲取業(yè)務類的地方,就都可以通過該工具類一步獲取到所需的業(yè)務類。代碼如下:
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<>();
/**
* 初始化方法,項目啟動時調(diào)用該方法來初始化map
* @param applicationContext spring 上下文對象
*/
public static void init(ApplicationContext applicationContext) {
List<IBaseHandler> handlers = new ArrayList<>();
applicationContext.getBeansOfType(IBaseHandler.class).forEach((name, obj) -> handlers.add(obj));
// 為了方便,兩次循環(huán)構建map,一次循環(huán)也可以解決,不過人為定義的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)方法,因此無法通過注入的方式來獲取到所有的IBaseHanlder,所以需要借助其他可注入IBaseHanlder的類來初始化管理對象,以下是方法:
/**
* 項目初始化類
* 繼承ApplicationContextAware,實現(xiàn)setApplicationContext,可獲取ApplicationContext來獲取上下文
*/
@Component
public class ApplicationInit implements ApplicationContextAware {
@Autowired
private List<IBaseHandler> handlers;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 調(diào)用處理器工具類初始化方法
HandlerManager.init(applicationContext);
}
}到此這篇關于SpringBoot頂層接口實現(xiàn)類注入項目的方法示例的文章就介紹到這了,更多相關SpringBoot類注入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mybatis Interceptor 攔截器的實現(xiàn)
這篇文章主要介紹了Mybatis Interceptor 攔截器的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12

