获取接口的所有实现

一、获取接口所有实现类

方法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@HfiTracepublic 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 {@Overridepublic 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 {@Overridepublic 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;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {// 通过上下文,根据接口类型返回相应的所有实现类beanuserServiceMap = 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 {@AutowiredOrderService orderService;@AutowiredDisCountStrageService disCountStrageService;@Testpublic 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.mzph.cn/news/30538.shtml

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

相关文章

Springboot中拦截GET请求获取请求参数验证合法性

目录 目的 核心方法 完整代码 创建拦截器 注册拦截器 测试效果 目的 在Springboot中创建拦截器拦截所有GET类型请求&#xff0c;获取请求参数验证内容合法性防止SQL注入&#xff08;该方法仅适用拦截GET类型请求&#xff0c;POST类型请求参数是在body中&#xff0c;所以下面…

3.1 计算机网络和网络设备

数据参考&#xff1a;CISP官方 目录 计算机网络基础网络互联设备网络传输介质 一、计算机网络基础 1、ENIAC&#xff1a;世界上第一台计算机的诞生 1946年2月14日&#xff0c;宾夕法尼亚大学诞生了世界上第一台计算机&#xff0c;名为电子数字积分计算机&#xff08;ENIAC…

【Autolayout案例02-距离四周边距 Objective-C语言】

一、好,来看第二个案例 1.第二个案例,是什么意思呢,第二个案例,要求屏幕中间,有一个UIView UIView,是个红色的UIView UIView的大小,我不限定 但是无论你是什么屏幕下 这个UIView距离上边,始终是50 距离右边,始终是50, 距离下边,始终是50, 距离左边,始终是5…

Nginx跳转模块——location与rewrite

一、location 1、location作用 用于匹配uri&#xff08;文件、图片、视频&#xff09; uri&#xff1a;统一资源标识符。是一种字符串标识&#xff0c;用于标识抽象的或物理资源文件、图片、视频 2、locatin分类 1、精准匹配&#xff1a;location / {...} 2、一般匹配&a…

PROFINET转DeviceNet网关普通网线能代替profinet吗

捷米JM-DNT-PN这款神器&#xff0c;连接PROFINET和DeviceNet网络&#xff0c;让两边数据轻松传输。 这个网关不仅从ETHERNET/IP和DEVICENET一侧读写数据&#xff0c;还可以将缓冲区数据交换&#xff0c;这样就可以在两个网络之间愉快地传递数据了&#xff01;而且&#xff0c;…

虚幻引擎游戏开发过程中,游戏鼠标如何双击判定?

UE虚幻引擎对于游戏开发者来说都不陌生&#xff0c;市面上有47%主机游戏使用虚幻引擎开发游戏。作为是一款游戏的核心动力&#xff0c;它的功能十分完善&#xff0c;囊括了场景制作、灯光渲染、动作镜头、粒子特效、材质蓝图等。本文介绍了虚幻引擎游戏开发过程中游戏鼠标双击判…

springboot+mybatis实现简单的增、删、查、改

这篇文章主要针对java初学者&#xff0c;详细介绍怎么创建一个基本的springboot项目来对数据库进行crud操作。 目录 第一步&#xff1a;准备数据库 第二步&#xff1a;创建springboot项目 方法1&#xff1a;通过spring官网的spring initilizer创建springboot项目 方法2&am…

SQL SERVER ip地址改别名

SQL server在使用链接服务器时必须使用别名&#xff0c;使用ip地址就会把192.188.0.2这种点也解析出来 解决方案&#xff1a; 1、物理机ip 192.168.0.66 虚拟机ip 192.168.0.115 2、在虚拟机上找到 C:\Windows\System32\drivers\etc 下的 &#xff08;我选中的文件&a…

C#与C/C++交互(1)——需要了解的基础知识

【前言】 C#中用于实现调用C/C的方案是P/Invoke&#xff08;Platform Invoke&#xff09;&#xff0c;让托管代码可以调用库中的函数。类似的功能&#xff0c;JAVA中叫JNI&#xff0c;Python中叫Ctypes。 常见的代码用法如下&#xff1a; [DllImport("Test.dll", E…

修改IDEA的idea.vmoptions参数导致IDEA无法打开(ReservedCodeCacheSize)

事发原因 Maven导依赖的时候OOM&#xff0c;因此怀疑是内存太小&#xff0c;尝试修改idea.vmoptions的参数&#xff0c;然后发现IDEA重启后打不开了&#xff0c;卸载重装后也无法打开。。。 实际上如果导包爆出OOM的话应该调整下图参数&#xff0c;不过这都是后话了 解决思路…

【从零开始学习JAVA | 第四十四篇】TCP协议中的握手与挥手

前言&#xff1a; TCP&#xff08;传输控制协议&#xff09;作为计算机网络中的重要协议&#xff0c;扮演着确保数据可靠传输的角色。在TCP的通信过程中&#xff0c;握手与挥手问题是不可忽视的关键环节。握手是指在建立连接时&#xff0c;客户端与服务器相互确认彼此的身份并…

【学习FreeRTOS】第1章——FreeRTOS入门

1.裸机与RTOS介绍 1.1.裸机与RTOS引入&#xff08;举例&#xff09; 设定情景&#xff1a;小明同学一边打游戏一边恢复女友消息&#xff0c;中途突然肚子疼要上医院 裸机的抽象表达 当紧急情况时&#xff0c;如果当前正在打游戏&#xff0c;那么小明只能打游戏和回复信息的流…

Spring 事务管理

目录 1. 事务管理 1.1. Spring框架的事务支持模型的优势 1.1.1. 全局事务 1.1.2. 本地事务 1.1.3. Spring框架的一致化编程模型 1.2. 了解Spring框架的事务抽象&#xff08;Transaction Abstraction&#xff09; 1.2.1. Hibernate 事务设置 1.3. 用事务同步资源 1.3.1…

PHP最简单自定义自己的框架创建目录结构(二)

1、mvc目录结构 2、目录解释 KJ&#xff1a;项目名称 core&#xff1a;框架核心目录 KJ.php 框架运行入口 index: 框架模块 controller:模块控制器 model:模块模型数据库操作 view:页面显示html index.php:index模块框架入口 3、index.php框架入口文件引入框架 <?php r…

虚拟世界探索:科技之下的未来可能性

随着科技的飞速发展&#xff0c;人们对于虚拟世界的憧憬和探索也日益加深。虚拟世界&#xff0c;那是一个超越现实的概念&#xff0c;一个充满想象力和创造力的领域。然而&#xff0c;虚拟世界究竟有可能实现吗&#xff1f;这是一个引人深思的问题。 虚拟世界&#xff0c;首先让…

Vue.js2+Cesium1.103.0 六、标绘与测量

Vue.js2Cesium1.103.0 六、标绘与测量 点&#xff0c;线&#xff0c;面的绘制&#xff0c;可实时编辑图形&#xff0c;点击折线或多边形边的中心点&#xff0c;可进行添加线段移动顶点位置等操作&#xff0c;并同时计算出点的经纬度&#xff0c;折线的距离和多边形的面积。 De…

mysql死锁分析show engine innodb status

文章目录 1、show engine innodb status命令2、前置知识3、无符号数、有符号数4、innodb关于有符号数的规定5、为什么会有这个规定 1、show engine innodb status命令 最近在使用mysql的show engine innodb status命令分析死锁&#xff0c;发现了一个有意思的点。就是红框里圈…

Docker 方式 部署 vue 项目 (docker + vue + nginx)

1.安装好 nginx 。 2. 把 vue 项目的源码克隆到确定目录下。用 git 管理&#xff0c;所以直接 git clone 到既定目录就行了。 如我的目录是&#xff1a;/root/jiangyu/projects/gentle_vue/gentle_vue_code 。 3. 项目打包&#xff1a; npm run build 复制 会自动生成 dist…

详解推送Git分支时发生的 cannot lock ref 错误

在码云上建了一个项目仓库,分支模型使用 git-flow ,并在本地新建了一个功能分支 feature/feature-poll。后来在推送时发生错误,提示 cannot lock ref ...... 这样的错误信息。下面复盘一下具体过程和解决办法,以供参考。 在码云中建立仓库时,考虑到想按照 GitFlow 的模式…