使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類
spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類
最近做項(xiàng)目,有個(gè)需求是和外部對接,從接口獲取新聞數(shù)據(jù),把數(shù)據(jù)和緩存中的數(shù)據(jù)對比,多了的添加到數(shù)據(jù)庫,少了的刪掉。
接口有兩個(gè),一開始我是在業(yè)務(wù)類里寫了兩個(gè)方法,代碼太長,簡單說就是兩個(gè)部分:
public Object saveANews() { //1、獲取A接口新聞列表 //2、和緩存對比,存數(shù)據(jù)到數(shù)據(jù)庫 } public Object saveBNews() { //1、獲取B新聞列表 //2、和緩存對比,存數(shù)據(jù)到數(shù)據(jù)庫 }
寫完后我發(fā)現(xiàn),因?yàn)椴僮鞯氖菙?shù)據(jù)庫的同一張表,2的部分代碼完全一模一樣,只有1的部分不同,而1的部分其實(shí)就只有一行代碼。。。
這必須得復(fù)用啊,而且是一個(gè)業(yè)務(wù),也沒必要分別用兩個(gè)方法,于是我改成了這樣:
//業(yè)務(wù)接口實(shí)現(xiàn)方法 public Object saveNews(NewsUtilService service) { //1、獲取接口新聞列表 List<NewsVO> list = service.queryNews(); //2、和緩存對比,存數(shù)據(jù)到數(shù)據(jù)庫 } //定義新聞數(shù)據(jù)接口 public interface NewsUtilService { List<NewsVO> queryNews(); } //接口的兩個(gè)實(shí)現(xiàn)類 @Service public class ANewsDataServiceImpl implements NewsUtilService { @Autowired private NewsDataMapper newsDataMapper; @Override public List<NewsVO> queryNews(){ //對接數(shù)據(jù) } } @Service public class BNewsDataServiceImpl implements NewsUtilService { @Override public List<NewsVO> queryNews(){ //對接數(shù)據(jù) } } //定義工廠類 @Service public class NewsUtilServiceFactory { /** * * Method Name: getNewsUtilService * @param source * @return */ public NewsUtilService getNewsUtilService(String source){ switch(source){ case "a": return new ANewsDataServiceImpl(); case "b": return new BNewsDataServiceImpl(); default: return null; } } } //控制層調(diào)用 @RestController public class NewsDataController { @Resource private NewsDataService newsDataService; @Resource private NewsUtilServiceFactory factory; public Object getNewsData(){ String[] sources = {"a","b"}; for (int i = 0; i < sources.length; i++) { NewsUtilService newsUtilService = factory.getNewsUtilService(sources[i]); newsDataService.saveNews(newsUtilService); } } }
本來以為這就大工告成了,誰知道運(yùn)行后控制臺(tái)居然報(bào)錯(cuò)了:
經(jīng)過一步步調(diào)試,總算發(fā)現(xiàn)了是什么問題:
其中一個(gè)實(shí)現(xiàn)類中注入的Mapper沒有實(shí)例化,是null。
一開始我還以為是構(gòu)造函數(shù)調(diào)用和注入的順序問題,查了半天才明白不是,問題在這里:
使用new關(guān)鍵字實(shí)例化的對象不是被spring創(chuàng)建的,不歸spring管,所以A類實(shí)現(xiàn)類中Mapper注入的注解根本不生效!
但是因?yàn)闃I(yè)務(wù)需要,那個(gè)mapper又需要用到,怎么辦呢?
當(dāng)時(shí)想到了兩種解決辦法
1、在接口的方法參數(shù)里加入mapper,把mapper作為參數(shù)傳進(jìn)去,但這實(shí)在太奇怪了,先不說B類實(shí)現(xiàn)類根本用不到mapper,而且一個(gè)接口定義出來后根本不管它的實(shí)現(xiàn)類吧,因?yàn)閷?shí)現(xiàn)類的問題去改接口,,,似乎有點(diǎn)非呀。
于是決定用第二種,修改工廠類變成如下:
//定義工廠類 @Service public class NewsUtilServiceFactory { @Autowired private ANewsDataServiceImpl aNewsDataServiceImpl; @Autowired private BNewsDataServiceImpl bNewsDataServiceImpl; public NewsUtilService getNewsUtilService(String source){ switch(source){ case "a": return aNewsDataServiceImpl; case "b": return bNewsDataServiceImpl; default: return null; } } }
代碼寫出來自己都無語了,先把所有的實(shí)現(xiàn)類都實(shí)例化出來,在根據(jù)輸入返回。這不是工廠模式,是商店模式吧。。。但是當(dāng)時(shí)也想不到其他辦法,就先這么寫了,但一直覺得肯定有其他解決方案,直到今天有空,去查了一下,才發(fā)現(xiàn)自己都多l(xiāng)ow。。。
其實(shí)spring可以動(dòng)態(tài)獲取實(shí)現(xiàn)類的~~~
@Service public class NewsUtilServiceFactory { @Autowired private ApplicationContext applicationContext; public NewsUtilService getNewsUtilService(String source){ switch(source){ case "web": return applicationContext.getBean(WebNewsDataServiceImpl.class); case "oa": return applicationContext.getBean(OANewDataServiceImpl.class); default: return null; } } }
這才是正確寫法有木有!
總算弄出來了,趕緊記錄下來先~
獲取某接口所有實(shí)現(xiàn)類
在springboot項(xiàng)目中,為了方便,我們可能需要獲取某一個(gè)接口下面的所有實(shí)現(xiàn)類,根據(jù)名稱進(jìn)行匹配使用。
正文
1、ServiceLocator.java
package com.yang.config; import com.yang.workOrder.service.IRootService; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.Map; /** * explain:獲取應(yīng)用上下文并獲取相應(yīng)的接口實(shí)現(xiàn)類 * * @author yang * @date 2021/1/5 */ @Component public class ServiceLocator implements ApplicationContextAware { /** * 用于保存接口實(shí)現(xiàn)類名及對應(yīng)的類 */ private Map<String, IRootService> map; /** * 獲取應(yīng)用上下文并獲取相應(yīng)的接口實(shí)現(xiàn)類 * @param applicationContext * @throws BeansException */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { //根據(jù)接口類型返回相應(yīng)的所有bean map = applicationContext.getBeansOfType(IRootService.class); } /** * 獲取所有實(shí)現(xiàn)集合 * @return */ public Map<String, IRootService> getMap() { return map; } /** * 獲取對應(yīng)服務(wù) * @param key * @return */ public IRootService getService(String key) { return map.get(key); } }
2、IRootService.java
package com.yang.workOrder.service; import com.alibaba.fastjson.JSONObject; import com.yang.workOrder.entity.WorkOrder; /** * explain:基礎(chǔ)流程操作服務(wù)接口 * * @author yang * @date 2021/1/5 */ public interface IRootService { /** * 開始流程 * @param workOrder * @return */ boolean startProcess(WorkOrder workOrder); }
3、RootA001ServiceImpl.java
package com.yang.workOrder.service.impl; import com.alibaba.fastjson.JSONObject; import com.yang.workOrder.entity.WorkOrder; import com.yang.workOrder.service.IRootService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; /** * explain:A_001流程審批實(shí)現(xiàn)類 * * @author yang * @date 2021/1/5 */ @Service("A_001") public class RootA001ServiceImpl implements IRootService { private static final Logger LOGGER = LoggerFactory.getLogger(RootA001ServiceImpl.class); @Override public boolean startProcess(WorkOrder workOrder) { return false; } }
4、RootA002ServiceImpl.java
package com.yang.workOrder.service.impl; import com.alibaba.fastjson.JSONObject; import com.yang.workOrder.entity.WorkOrder; import com.yang.workOrder.service.IRootService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; /** * explain:A_002流程審批實(shí)現(xiàn)類 * * @author yang * @date 2021/1/5 */ @Service("A_002") public class RootA002ServiceImpl implements IRootService { private static final Logger LOGGER = LoggerFactory.getLogger(RootA002ServiceImpl.class); @Override public boolean startProcess(WorkOrder workOrder) { return false; } }
結(jié)果
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot 實(shí)例化bean如何選擇代理方式
這篇文章主要為大家介紹了Spring Boot實(shí)例化bean如何選擇代理方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07servlet實(shí)現(xiàn)文件上傳、預(yù)覽、下載、刪除功能
這篇文章主要為大家詳細(xì)介紹了servlet實(shí)現(xiàn)文件上傳、預(yù)覽、下載、刪除功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09java連接SQL Server數(shù)據(jù)庫的方法
這篇文章主要為大家詳細(xì)介紹了java連接SQL Server數(shù)據(jù)庫的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Springboot使用@WebListener?作為web監(jiān)聽器的過程解析
這篇文章主要介紹了Springboot使用@WebListener作為web監(jiān)聽器的過程,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08通過java api實(shí)現(xiàn)解壓縮zip示例
這篇文章主要介紹了通過java api實(shí)現(xiàn)解壓縮zip示例,需要的朋友可以參考下2014-04-04SpringBoot整合Mybatis,解決TypeAliases配置失敗的問題
這篇文章主要介紹了SpringBoot整合Mybatis,解決TypeAliases配置失敗的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Java利用SpEL表達(dá)式實(shí)現(xiàn)權(quán)限校驗(yàn)
這篇文章主要為大家詳細(xì)介紹了Java如何利用SpEL表達(dá)式實(shí)現(xiàn)權(quán)限校驗(yàn)功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01JavaWeb簡單文件上傳流程的實(shí)戰(zhàn)記錄
在Web應(yīng)用系統(tǒng)開發(fā)中,文件上傳和下載功能是非常常用的功能,下面這篇文章主要給大家介紹了關(guān)于JavaWeb實(shí)現(xiàn)簡單文件上傳流程的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03