溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類

發(fā)布時(shí)間:2022-02-25 14:01:55 來(lái)源:億速云 閱讀:454 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇“如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類”文章吧。

spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類

最近做項(xiàng)目,有個(gè)需求是和外部對(duì)接,從接口獲取新聞數(shù)據(jù),把數(shù)據(jù)和緩存中的數(shù)據(jù)對(duì)比,多了的添加到數(shù)據(jù)庫(kù),少了的刪掉。

接口有兩個(gè),一開(kāi)始我是在業(yè)務(wù)類里寫了兩個(gè)方法,代碼太長(zhǎng),簡(jiǎn)單說(shuō)就是兩個(gè)部分:

public Object saveANews() {
	//1、獲取A接口新聞列表
    //2、和緩存對(duì)比,存數(shù)據(jù)到數(shù)據(jù)庫(kù)
}
 
public Object saveBNews() {
	//1、獲取B新聞列表
    //2、和緩存對(duì)比,存數(shù)據(jù)到數(shù)據(jù)庫(kù)
}

寫完后我發(fā)現(xiàn),因?yàn)椴僮鞯氖菙?shù)據(jù)庫(kù)的同一張表,2的部分代碼完全一模一樣,只有1的部分不同,而1的部分其實(shí)就只有一行代碼。。。

這必須得復(fù)用啊,而且是一個(gè)業(yè)務(wù),也沒(méi)必要分別用兩個(gè)方法,于是我改成了這樣:

//業(yè)務(wù)接口實(shí)現(xiàn)方法
public Object saveNews(NewsUtilService service) {
	//1、獲取接口新聞列表
    List<NewsVO> list = service.queryNews();
    //2、和緩存對(duì)比,存數(shù)據(jù)到數(shù)據(jù)庫(kù)
}
 
//定義新聞數(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(){
		//對(duì)接數(shù)據(jù)
	}
}
 
@Service
public class BNewsDataServiceImpl implements NewsUtilService {
    @Override
	public List<NewsVO> queryNews(){
		//對(duì)接數(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);
			}
    }
}

本來(lái)以為這就大工告成了,誰(shuí)知道運(yùn)行后控制臺(tái)居然報(bào)錯(cuò)了:

如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類

經(jīng)過(guò)一步步調(diào)試,總算發(fā)現(xiàn)了是什么問(wèn)題:

如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類

其中一個(gè)實(shí)現(xiàn)類中注入的Mapper沒(méi)有實(shí)例化,是null。

一開(kāi)始我還以為是構(gòu)造函數(shù)調(diào)用和注入的順序問(wèn)題,查了半天才明白不是,問(wèn)題在這里:

如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類

使用new關(guān)鍵字實(shí)例化的對(duì)象不是被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í)在太奇怪了,先不說(shuō)B類實(shí)現(xiàn)類根本用不到mapper,而且一個(gè)接口定義出來(lái)后根本不管它的實(shí)現(xiàn)類吧,因?yàn)閷?shí)現(xiàn)類的問(wè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;
		}
	}
}

代碼寫出來(lái)自己都無(wú)語(yǔ)了,先把所有的實(shí)現(xiàn)類都實(shí)例化出來(lái),在根據(jù)輸入返回。這不是工廠模式,是商店模式吧。。。但是當(dāng)時(shí)也想不到其他辦法,就先這么寫了,但一直覺(jué)得肯定有其他解決方案,直到今天有空,去查了一下,才發(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;
		}
	}
}

這才是正確寫法有木有!

總算弄出來(lái)了,趕緊記錄下來(lái)先~

獲取某接口所有實(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)類名及對(duì)應(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;
    }
    /**
     * 獲取對(duì)應(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 {
    /**
     * 開(kāi)始流程
     * @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é)果

如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類

以上就是關(guān)于“如何使用spring動(dòng)態(tài)獲取接口的不同實(shí)現(xiàn)類”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI