使用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