当前位置: 首页 > 科技观察

字节面试也会问SPI机制?

时间:2023-03-16 11:25:30 科技观察

1。前言JavaSPI机制主要是类加载器的反双亲委派的实现(jdk路径中没有指定第三方包,一般的类加载器无法加载,需要专门的ContextClassLoader来加载)使用)。本次将详细讲解SPI机制,并结合案例介绍其在实际场景中的具体使用。提示:以下为本文正文内容,案例仅供对比参考。2、什么是SPI机制?SPI(全称:ServiceProviderInterface)是jdk内置的一种服务提供者发现接口机制,旨在被第三方服务作为组件实现或扩展,方便开发者快速集成指定的扩展组件,满足指定的需求。对于应用程序或平台扩展来说,这无疑是一种低成本、动态灵活的解决方案。SPI机制调度流程(业务调用方可根据加载的扩展实现类实现功能)调用流程三、实现方法及使用场景针对当前实际项目范围,总结了常见的应用场景。3.1指定接口权限文件名的方法是在资源文件下创建META/services/目录,并在该目录下新建文件。文件名是接口分类权限的文件名,如com.lgy.spidemo.serviceway.SpiService。(可惜是接口类的包地址+接口类名)使用场景一:场景描述:不同部门类型的员工需要从不同的考勤应用中获取考勤信息。比如职能部门只拉钉钉考勤,业务部门需要在拉钉钉考勤的基础上,结合自研考勤模块数据,汇总考勤结果。实现方法:抽象通用拉取考勤接口,定义不同部门考勤统计的实现类。直接上传代码:通用接口:packagecom.lgy.spidemo.serviceway;/***@description:考勤接口**/publicinterfaceAttendanceService{voidpullAttendanceInfos();}职能部门考勤实施班;/***@description:职能部门考勤实现**/publicclassFunctionAttendanceServiceImplimplementsAttendanceService{@OverridepublicvoidpullAttendanceInfos(){System.out.println("FunctionAttendanceServiceimplements...");//逻辑忽略}}销售部考勤实现;/***@description:销售部考勤实现**/publicclassSaleAttendanceServiceImplimplementsAttendanceService{@OverridepublicvoidpullAttendanceInfos(){System.out.println("SaleAttendanceServiceimplements...");//逻辑忽略}}测试类;/***1.在项目的\src\main\resources\下创建一个\META-INF\services目录*2.在META-INF\services目录下再添加一个配置文件。这个文件必须使用接口的全限定类名称要一致(com.lgy.spidemo.service.SpiService)*3.在配置文件中写入具体实现类的全限定类名。如果不止一个,则另起一行写上com.lgy.spidemo.service.impl。SaleAttendanceServiceImplcom.lgy.spidemo.service.impl.FunctionAttendanceServiceImpl**/公共类AttendanceServiceTest{publicstaticvoidmain(String[]args){ServiceLoaderservices=ServiceLoader.load(AttendanceService.class);//省略判断人事部门类型的逻辑//测试输出结果,显示已经加载实现接口for(AttendanceServiceservice:services){service.pullAttendanceInfos();}}}测试结果如下;//两个实现类都加载成功。在实际使用中,可以根据需要调用不同的实现。FunctionAttendanceService实现...SaleAttendanceService实现。...不要在实现类上打任何注解,否则Spring会在初始化过程中扫描加载,无法测试。结合场景一分析:该场景通过自定义实现类来满足业务需求(不同部门的考勤规则),有助于业务实现快速迭代,同时也提高了服务架构的可扩展性。考虑到公司组织结构比较复杂,部门职责比较细化,后续扩容的概率比较大。例如,职能部门行政和业务标准的细分,很可能会增加出勤率以外的各种考核指标。借鉴这个方案可能实现简单,集成起来更方便,减少业务之间的依赖,实现解耦的设计模式,所以个人比较喜欢使用这个方案。其他应用:比如项目中常用的日志也使用了SPI机制。常见的common-loggingLogFatory是标准的SPI接口。有兴趣的可以自行研究。3.2spring.factories方法同上,需要在资源文件下创建一个META/services/目录,并在该目录下新建一个文件,不同的是文件名为spring.factories。场景二场景描述:根据不同开发端的使用习惯展示不同的接口文档。比如APP端习惯Swagger,JAVA端喜欢dateway风格,所以在不同的实例中展示不同的接口文档。这个场景是我的想象。实现方法:构建1.0.0-swagger和2.0.0-dataway等两个版本的jar包,然后在对应包中的spring.factories中配置config配置类。代码如下:packagecom.lgy.spidemo.factoriesway;导入org.springframework.boot.autoconfigure.AutoConfigurationImportEvent;导入org.springframework.boot.autoconfigure.AutoConfigurationImportListener;/***@description:自动配置swagger**/publicclassSwaggetAutoConfiguration{publicSwaggetAutoConfiguration(){System.out.println("SwaggetAutoConfigurationinit...");}//配置内容省略}/***@description:自动配置dataway**/publicclassDataWayAutoConfiguration{publicDataWayAutoConfiguration(){System.out.println("DataWayAutoConfigurationinit...");}//配置内容省略}/***resource/META-INFO/spring.factories文件内容**org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.lgy.spidemo.factoriesway.SwaggetAutoConfiguration*输出结果:SwaggetAutoConfigurationinit...**/根据spring.factories中配置的类,在springboot启动初始化过程中会自动加载相应的配置,实现所需的接口文件。结合场景2分析:spring.factories的实现机制与上述方法相同,只是实现方式不同。本质目的是通过抽象类实现解耦,最终方便扩展其他使用场景:比如spring-boot-autoconfigure-x.x.x.RELEASE.jar,就是这种完成初始加载的方式。4.小结这次讲解的两种方法都是基于SPI机制的,可见其在开发中的受欢迎程度。当然,有很多方法可以实现。我个人认为最重要的是在自己能控制的范围内使用。毕竟有些问题是可以通过自己的学习和理解来解决的。最后,没有更好的技术知识,只有更合适的技术应用,结合实际,检测真相。