文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何使用spring动态获取接口的不同实现类

2023-06-29 07:40

关注

这篇“如何使用spring动态获取接口的不同实现类”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“如何使用spring动态获取接口的不同实现类”文章吧。

spring动态获取接口的不同实现类

最近做项目,有个需求是和外部对接,从接口获取新闻数据,把数据和缓存中的数据对比,多了的添加到数据库,少了的删掉。

接口有两个,一开始我是在业务类里写了两个方法,代码太长,简单说就是两个部分:

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();} //接口的两个实现类@Servicepublic class ANewsDataServiceImpl implements NewsUtilService {     @Autowiredprivate NewsDataMapper newsDataMapper;     @Overridepublic List<NewsVO> queryNews(){//对接数据}} @Servicepublic class BNewsDataServiceImpl implements NewsUtilService {    @Overridepublic List<NewsVO> queryNews(){//对接数据}} //定义工厂类@Servicepublic class NewsUtilServiceFactory {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);}    }}

本来以为这就大工告成了,谁知道运行后控制台居然报错了:

如何使用spring动态获取接口的不同实现类

经过一步步调试,总算发现了是什么问题:

如何使用spring动态获取接口的不同实现类

其中一个实现类中注入的Mapper没有实例化,是null。

一开始我还以为是构造函数调用和注入的顺序问题,查了半天才明白不是,问题在这里:

如何使用spring动态获取接口的不同实现类

使用new关键字实例化的对象不是被spring创建的,不归spring管,所以A类实现类中Mapper注入的注解根本不生效!

但是因为业务需要,那个mapper又需要用到,怎么办呢?

当时想到了两种解决办法

在接口的方法参数里加入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 {@Autowiredprivate 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项目中,为了方便,我们可能需要获取某一个接口下面的所有实现类,根据名称进行匹配使用。

正文

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;@Componentpublic class ServiceLocator implements ApplicationContextAware {        private Map<String, IRootService> map;        @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        //根据接口类型返回相应的所有bean        map = applicationContext.getBeansOfType(IRootService.class);    }        public Map<String, IRootService> getMap() {        return map;    }        public IRootService getService(String key) {        return map.get(key);    }}

IRootService.java

package com.yang.workOrder.service;import com.alibaba.fastjson.JSONObject;import com.yang.workOrder.entity.WorkOrder;public interface IRootService {        boolean startProcess(WorkOrder workOrder);}

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;@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;    }}

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;@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动态获取接口的不同实现类

以上就是关于“如何使用spring动态获取接口的不同实现类”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯