获取接口的所有实现

news2024/12/24 20:57:44

一、获取接口所有实现类

方法1:JDK自带的ServiceLoader实现
ServiceLoader是JDK自带的一个类加载器,位于java.util包当中,作为 A simple service-provider loading facility。

(1)创建接口

package com.example.demo.service;

import java.text.ParseException;

public interface UserService{

    void register() throws ParseException;
}

(2)创建实现类
第一个实现类UserServiceImpl

package com.example.demo.service.impl;

import com.example.demo.common.HfiTrace;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    public UserServiceImpl(UserServiceImpl2 userServiceImpl2) { //由于构造函数先于依赖注入执行,所以这里执行的时候postConstructTest2还没有注入,所以报错
        userServiceImpl2.register();
    }

    @Override
    @HfiTrace
    public void register(){
        System.out.println("register user");
    }
}

第二个实现类 UserServiceImpl2

package com.example.demo.service.impl;

import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl2 implements UserService {

    @Override
    public void register(){
        System.out.println("register user");
    }
}

第三个实现类 UserServiceImpl3

package com.example.demo.service.impl;

import com.example.demo.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl3 implements UserService {

    @Override
    public void register(){
        System.out.println("register user 3");
    }
}

(3)在resources目录下添加:META-INF/services/目录,新增一个文件:用你的接口全路径名称命名一个文件(不加后缀),然后在该文件中一行一个添加你的接口实现类的全路径名。
在这里插入图片描述
(4)在第三步新增的文件中,添加接口所有实现类的全路径名,如:
在这里插入图片描述
(5)测试

ServiceLoader<UserService> load = ServiceLoader.load(UserService.class);

        Iterator<UserService> it = load.iterator();
        while (it.hasNext()) {
            UserService service = it.next();
            service.register();
        }

        //for(UserService userService : load){
        //    userService.register();
        //}

方法2:使用Spring自带的方法
Application.getBeansOfType();
Spring作为一个容器,管理着一个项目中所有经过配置的Java类(xml配置文件或Annotation方式)。如果某个接口的所有实现类均被Spring托管了,那么通过Spring就可以很简单的返回这些实现类。

@Component
public class userServiceLocator implements ApplicationContextAware {
	/**
	 * 存储 UserService接口的所有实现类
	 */
	private Map<String, UserService> userServiceMap;
	private List<UserService> userServiceList;
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// 通过上下文,根据接口类型返回相应的所有实现类bean
		userServiceMap = applicationContext.getBeansOfType(UserService.class);
		userServiceList = new ArrayList<>(userServiceMap.values());
	}
	
	/**
	 * 获取所有实现类
	 *
	 * @return
	 */
	public Map<String, UserService> getAllMap() {
		return userServiceMap;
	}

	/**
	 * 通过名称获取某个实现类
	 *
	 * @param beanName
	 *            bean名字
	 * @return
	 */
	private UserService getByName(String beanName) {
		return userServiceMap.get(beanName);
	}

	/**
	 * 获取所有实现类
	 *
	 * @return
	 */
	public List<UserService> getAllList() {
		return userServiceList;
	}

	/**
	 * 根据枚举获取某个实现类
	 *
	 * @param xxxTypeEnum
	 * @return
	 */
	public UserService get(XxxTypeEnum xxxTypeEnum) {
		UserService xxxService = userServiceList.stream().filter(s -> s.isSupport(xxxTypeEnum))
				.collect(Collectors.toList()).get(0);
		return xxxService;
	}

}

二、策略模式典型应用

spring自动注入接口的多个实现类(结合策略设计模式)
在使用spring开发的时候,有时候会出现一个接口多个实现类的情况,但是有没有有时候有这样一种情况,就是你的逻辑代码里面还不知道你需要使用哪个实现类,就是比如说:你去按摩,按摩店里面有几种会员打折,比如有,vip、svip和普通用户,那按摩店里面是不是需要对这些会员定义好不同的折扣,然后根据每个用户不同的会员计算出不同的消费情况

虽然这样的情况,对于一般人来说,第一眼肯定就是说,直接加 if else 去判断就可以了

这样做,对于实现功能而言,肯定是没问题,如果以后这个按摩店又增加一种会员,那你是不是又要去修改你的逻辑代码去在加一个 if else ,这样就违反了系统架构设计的开闭原则,这样写if else 也使你的代码看起来不优雅。

在代码里面,我们可以先定义一个DiscountStrategy接口类

//顶层会员接口,这个接口的实现类有多个

public interface DiscountStrategy {
    public String getType();
    public double disCount(double fee);
 
}

然后在写他的几个实现类

/**
普通用户实现类
*/
@Service
public class NormalDisCountService implements  DiscountStrategy {
 
    public String getType(){
        return "normal";
    }
 
    public double disCount(double fee){
        return fee * 1;
    }
 
}
/**
会员实现类
*/
@service
public class VipDisCountService  implements  DiscountStrategy{
 
    public String getType(){
        return "vip";
    }
 
    public double disCount(double fee){
        return fee * 0.8;
    }
 
}
/**
svip超级会员实现类
*/
@Service
public class SVipDisCountService  implements  DiscountStrategy {
 
    public String getType(){
        return "svip";
    }
 
    public double disCount(double fee){
        return fee * 0.5;
    }
 
}

解决方案
然后当一个用户进来消费的时候,根据你当前的身份去打折扣

定义一个map集合,然后把所有的实现类都放入到这个集合中,然后根据当前的会员类型去进行不同的操作

@Service
public class DisCountStrageService {
    Map<String,DiscountStrategy> discountStrategyMap = new HashMap<>();
    // 构造函数,如果你是集合接口对象,那么久会把spring容器中所有关于该接口的子类,全部抓出来放入到集合中
    @Authwired 
    public DisCountStrageService(List<DiscountStrategy> discountStrategys){
        for (DiscountStrategy discountStrategy: discountStrategys) {
            discountStrategyMap.put(discountStrategy.getType(),discountStrategy);
        }
    }
 
    public double disCount(String type,Double fee){
        DiscountStrategy discountStrategy =discountStrategyMap.get(type);
        return discountStrategy.disCount(fee);
    }
}

测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class MzySpringModeApplicationTests {
 
    @Autowired
    OrderService orderService;
 
    @Autowired
    DisCountStrageService disCountStrageService;
 
    @Test
    public void contextLoads() {
        //orderService.saveOrder();
        double vipresult = disCountStrageService.disCount("vip",100d);
        double svipresult = disCountStrageService.disCount("svip",100d);
        double normalresult = disCountStrageService.disCount("normal",100d);
        System.out.println(vipresult);
        System.out.println(svipresult);
        System.out.println(normalresult);
    }
}

其实这就是java设计模式的策略模式,只不过就是用构造函数注入到list集合中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/860849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lua 数据类型 —— 字符串

一、字符串 Lua 使用 八个比特位来存储 字符。&#xff08;一个字节 八个比特位&#xff09; Lua 最好使用 UTF-8 编码。 字符串是不可变值&#xff0c;和 java 和 kotlin 相似&#xff0c;修改其中某一个字符&#xff0c;都是创建一个新的字符串。 Lua 对字符串会进行自动…

Python进阶(二)

前言&#xff1a;本篇博客主要记录Python进程的创建、进程间的通信、进程池的使用、线程的创建、多线程的执行、同步和互斥、协程的创建和应用。 目录 思维导图 基本概念 进程 进程的创建 进程间的通信 进程池 线程 线程的创建 子线程的执行顺序 同步&互斥 互斥…

惊讶,日本用“Excel”作画,中国却用“Excel”造“另类”软件

精益求精 表格是一项伟大的创造&#xff0c;它的出现改变了人类记录、分析和展示数据的方式。 随着科技的日益月异的更新&#xff0c;从最早的纸质表格到现代化的电子表格&#xff0c;人类对表格的改造也在不断的升级和进步。 最初的纸质表格的简单记录&#xff0c;无法进行复…

企业权限管理(八)-登陆使用数据库认证

Spring Security 使用数据库认证 在 Spring Security 中如果想要使用数据进行认证操作&#xff0c;有很多种操作方式&#xff0c;这里我们介绍使用 UserDetails 、 UserDetailsService来完成操作。 UserDetails public interface UserDetails extends Serializable { Collecti…

汇聚行业精英,共探创新之道:首届NDI生态系统行业峰会即将登陆北京!

IP化和轻量化是媒体制播技术发展的主要趋势。为了推进媒体行业的IP制播技术应用发展&#xff0c;提供一个专业、全面的媒体技术交流平台&#xff0c;长沙千视电子科技有限公司将联合NDI官方、NDI生态产品厂家和NDI技术应用媒体单位于2023年8月22日在北京举办国内首届NDI生态系统…

嵌入式开发学习(STC51-11-中断系统)

内容 外部中断-使用独立按键K3控制LED亮灭&#xff1b; 定时器&#xff08;中断&#xff09;-通过定时器0中断控制D1指示灯间隔1秒闪烁&#xff1b; 串口通信&#xff08;中断&#xff09;-通过串口&#xff08;UART&#xff09;实现与PC机对话&#xff0c;51单片机的串口收…

Leetcode算法递归类—合并两个有序链表

目录 21. 合并两个有序链表 题解&#xff1a; 代码&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&a…

logstash 采集 docker 日志

1、nginx容器部署 参考&#xff1a;nginx容器部署 将容器内的nginx日志文件映射到宿主机/home/logs/nginx目录下 注意&#xff1a;并且需要需要将日志的输出格式修改为json 2、编辑vim /opt/logstash-7.4.2/config/nginx-log-es.conf 文件&#xff0c;收集docker nginx容器日…

【时间格式引发的事故】

时间格式引发的事故 背景实战演示结论 背景 前不久写了一个删除数据接口&#xff0c;条件是根据时间删除时间后面的数据。入参是 时间字符串。后台的时间格式 是 yyyyMMdd。然后当时前端传参数的时候&#xff0c;随意的传了2023-07-31的时间&#xff0c;然后将该表的数据全部删…

CCLINK IE转MODBUS-TCP网关modbus tcp协议详解

你是否曾经遇到过需要同时处理CCLINK IE FIELD BASIC和MODBUS两种数据协议的情况&#xff1f;捷米的JM-CCLKIE-TCP网关可以帮助你解决这个问题。 捷米JM-CCLKIE-TCP网关可以分别从CCLINK IE FIELD BASIC一侧和MODBUS一侧读写数据&#xff0c;然后将数据存入各自的缓冲区。接着…

【学习】若依源码(前后端分离版)之 “ 用户管理根据不同角色、部门显示数据范围”

大型纪录片&#xff1a;学习若依源码&#xff08;前后端分离版&#xff09;之 “ 用户管理根据不同角色、部门显示数据范围” 前端部分后端部分“ /list " 方法" /treeselect " 方法 结语 起因是我想做一个根据不同角色以及其所在的部门展示其相应的信息&#x…

StarRocks 3.1重磅发布,云原生湖仓新范式再升级!

StarRocks 自4月底发布3.0版本&#xff0c;拥抱云原生&#xff0c;开启极速统一的湖仓新范式&#xff1b;8月7日&#xff0c;StarRocks 正式发布全新3.1版本&#xff0c;全面提升云原生存算分离构架、极速数据湖分析、物化视图等重量级特性&#xff0c;让用户更简单的实现极速统…

前端性能优化之性能优化的指标和工具(chrome devtools、lighthouse、webpagetest)

文章目录 引言一、为什么要进行web性能优化二、RAIL测量模型1. 什么是RAIL2. 性能测量工具 三、性能测量工具的使用和性能指标以及优化目标1. Chrome DevTools1. 打开调试工具方式和配置2. network下的几个性能指标1. requests 请求总数2. transferred实际从服务器下载的数据量…

uni-app:实现点击按钮,进行数据累加展示(解决数据过多,导致出错)

效果 代码 核心代码 一、标签显示 <!-- 加载更多 --> <view class"load_more" v-if"info.length > pageNum * pageSize" tap"loadMore">加载更多 </view> v-if"info.length > pageNum * pageSize"&#xf…

主数据管理案例-某研究所

1、 背景介绍及难点分析 某军工研究所是机电类科研生产一体化研究所&#xff0c;具有多品种、小批量、离散性、央企、军工保密等特点&#xff0c;在数据管理系统和研制管理体系的控制下&#xff0c;设计、工艺、 制造、试验、售后服务等环节都产生了大量的数据。在管理信息化、…

影像维修工程师专项技能培训

最近遇到很多咨询的人员都在对医疗行业产生疑惑&#xff0c;新闻报道说很多医院、公司的领导都被查&#xff0c;这样会不会影响设备维修方面&#xff0c;对后期找工作等有没有影响&#xff1f;总不能学好了技术却没有发挥的余地&#xff1f; 最近确实是国家整体在对医疗方面做…

Win11 VS2022 配置CGAL-5.6

由于项目要用到几何库CGAL&#xff0c;因此做了配置。采用的是官方文档中的“Installing from the Source Archive”方式。 1. 下载安装CGAL &#xff08;1&#xff09;CGAL-5.6.zip下载地址&#xff1a;Releases CGAL/cgal GitHub 下载下图所示的两个文件。 &#xff08…

LeetCode面向运气之Javascript—第27题-移除元素-98.93%

LeetCode第27题-移除元素 题目要求 一个数组nums和一个值val&#xff0c;你需要原地移除所有数值等于val的元素&#xff0c;并返回移除后数组的新长度 举例 输入&#xff1a;nums [3,2,2,3], val 3 输出&#xff1a;2, nums [2,2] 输入&#xff1a;nums [0,1,2,2,3,0,4,2…

【C++】——模板

目录 泛型编程函数模板函数模板的概念函数模板格式&#xff1a;函数模板的原理函数模板的实例化模板参数的匹配原则 类模板类模板定义格式类模板的实例化 泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础 引例…

并发——线程池实践

文章目录 1. 使用 ThreadPoolExecutor 的构造函数声明线程池2.监测线程池运行状态3.建议不同类别的业务用不同的线程池4.别忘记给线程池命名5.正确配置线程池参数常规操作美团的骚操作 简单总结一下我了解的使用线程池的时候应该注意的东西&#xff0c;网上似乎还没有专门写这…