spring動態獲取介面的不同實現類
阿新 • • 發佈:2019-01-01
最近做專案,有個需求是和外部對接,從介面獲取新聞資料,把資料和快取中的資料對比,多了的新增到資料庫,少了的刪掉。介面有兩個,一開始我是在業務類裡寫了兩個方法,程式碼太長,簡單說就是兩個部分:
public Object saveANews() {
//1、獲取A介面新聞列表
//2、和快取對比,存資料到資料庫
}
public Object saveBNews() {
//1、獲取B新聞列表
//2、和快取對比,存資料到資料庫
}
寫完後我發現,因為操作的是資料庫的同一張表,2的部分程式碼完全一模一樣,只有1的部分不同,而1的部分其實就只有一行程式碼。。。
這必須得複用啊,而且是一個業務,也沒必要分別用兩個方法,於是我改成了這樣:
//業務介面實現方法 public Object saveNews(NewsUtilService service) { //1、獲取介面新聞列表 List<NewsVO> list = service.queryNews(); //2、和快取對比,存資料到資料庫 } //定義新聞資料介面 public interface NewsUtilService { List<NewsVO> queryNews(); } //介面的兩個實現類 @Service public class ANewsDataServiceImpl implements NewsUtilService { @Autowired private NewsDataMapper newsDataMapper; @Override public List<NewsVO> queryNews(){ //對接資料 } } @Service public class BNewsDataServiceImpl implements NewsUtilService { @Override public List<NewsVO> queryNews(){ //對接資料 } } //定義工廠類 @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; } } } //控制層呼叫 @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); } } }
本來以為這就大工告成了,誰知道執行後控制檯居然報錯了:
經過一步步除錯,總算髮現了是什麼問題:
其中一個實現類中注入的Mapper沒有例項化,是null。
一開始我還以為是建構函式呼叫和注入的順序問題,查了半天才明白不是,問題在這裡:
使用new關鍵字例項化的物件不是被spring建立的,不歸spring管,所以A類實現類中Mapper注入的註解根本不生效!
但是因為業務需要,那個mapper又需要用到,怎麼辦呢?
當時想到了兩種解決辦法:1、在介面的方法引數里加入mapper,把mapper作為引數傳進去,但這實在太奇怪了,先不說B類實現類根本用不到mapper,而且一個介面定義出來後根本不管它的實現類吧,因為實現類的問題去改介面,,,似乎有點非呀。
於是決定用第二種,修改工廠類變成如下:
//定義工廠類
@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;
}
}
}
程式碼寫出來自己都無語了,先把所有的實現類都例項化出來,在根據輸入返回。這不是工廠模式,是商店模式吧。。。但是當時也想不到其他辦法,就先這麼寫了,但一直覺得肯定有其他解決方案,直到今天有空,去查了一下,才發現自己都多low。。。
其實spring可以動態獲取實現類的~~~
@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;
}
}
}
這才是正確寫法有木有!
總算弄出來了,趕緊記錄下來先~