如何使用spring动态获取接口的不同实现类
这篇"如何使用spring动态获取接口的不同实现类"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"如何使用spring动态获取接口的不同实现类"文章吧。
spring动态获取接口的不同实现类
最近做项目,有个需求是和外部对接,从接口获取新闻数据,把数据和缓存中的数据对比,多了的添加到数据库,少了的删掉。
接口有两个,一开始我是在业务类里写了两个方法,代码太长,简单说就是两个部分:
public Object saveANews() { //1、获取A接口新闻列表 //2、和缓存对比,存数据到数据库} public Object saveBNews() { //1、获取B新闻列表 //2、和缓存对比,存数据到数据库}
写完后我发现,因为操作的是数据库的同一张表,2的部分代码完全一模一样,只有1的部分不同,而1的部分其实就只有一行代码。。。
这必须得复用啊,而且是一个业务,也没必要分别用两个方法,于是我改成了这样:
//业务接口实现方法public Object saveNews(NewsUtilService service) { //1、获取接口新闻列表 Listlist = service.queryNews(); //2、和缓存对比,存数据到数据库} //定义新闻数据接口public interface NewsUtilService { List queryNews();} //接口的两个实现类@Servicepublic class ANewsDataServiceImpl implements NewsUtilService { @Autowired private NewsDataMapper newsDataMapper; @Override public List queryNews(){ //对接数据 }} @Servicepublic class BNewsDataServiceImpl implements NewsUtilService { @Override public List queryNews(){ //对接数据 }} //定义工厂类@Servicepublic 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; } }} //控制层调用@RestControllerpublic 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,而且一个接口定义出来后根本不管它的实现类吧,因为实现类的问题去改接口,,,似乎有点非呀。
于是决定用第二种,修改工厂类变成如下:
//定义工厂类@Servicepublic 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可以动态获取实现类的~~~
@Servicepublic 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; } }}
这才是正确写法有木有!
总算弄出来了,赶紧记录下来先~
获取某接口所有实现类
在springboot项目中,为了方便,我们可能需要获取某一个接口下面的所有实现类,根据名称进行匹配使用。
正文
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:获取应用上下文并获取相应的接口实现类 * * @author yang * @date 2021/1/5 */@Componentpublic class ServiceLocator implements ApplicationContextAware { /** * 用于保存接口实现类名及对应的类 */ private Mapmap; /** * 获取应用上下文并获取相应的接口实现类 * @param applicationContext * @throws BeansException */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { //根据接口类型返回相应的所有bean map = applicationContext.getBeansOfType(IRootService.class); } /** * 获取所有实现集合 * @return */ public Map getMap() { return map; } /** * 获取对应服务 * @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:基础流程操作服务接口 * * @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流程审批实现类 * * @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流程审批实现类 * * @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; }}
结果
以上就是关于"如何使用spring动态获取接口的不同实现类"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。