我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

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

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用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();
}
 
//接口的两个实现类
@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 {	
	
	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;
		}
	}
}

这才是正确写法有木有!

总算弄出来了,赶紧记录下来先~

获取某接口所有实现类

在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;

@Component
public 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);
    }
}

2、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);
}

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;

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

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

结果

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

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

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

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

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

怎么使用Spring特性实现接口多类的动态调用

今天小编给大家分享一下怎么使用Spring特性实现接口多类的动态调用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。正好用到。
2023-06-29

springboot怎么通过不同的策略动态调用不同的实现类

这篇“springboot怎么通过不同的策略动态调用不同的实现类”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springb
2023-06-29

vue中如何使用echarts实现动态数据绑定及获取后端接口数据

本篇内容主要讲解“vue中如何使用echarts实现动态数据绑定及获取后端接口数据”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue中如何使用echarts实现动态数据绑定及获取后端接口数据”
2023-07-02

使用Golang接口类型实现参数的多态化

使用 go 语言接口类型可以实现参数多态化,使函数或方法可以接受实现相同接口的不同类型参数,如示例中计算不同形状面积的函数 calculatearea。在实际应用中,接口类型可增强函数灵活性,实现多态行为和创建可扩展框架,如持久化框架中针对
使用Golang接口类型实现参数的多态化
2024-04-13

在Jav中使用httpclient与Jsoup实现获取动态生成的数据

这期内容当中小编将会给大家带来有关在Jav中使用httpclient与Jsoup实现获取动态生成的数据,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java爬虫Jsoup+httpclient获取动态生成
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录