八股文背多了,相信大家都听说过一个词, spi扩展 。
有的面试官就很喜欢问这个问题,springboot的自动装配是如何实现的?
基本上,你一说是基于spring的spi扩展机制,再把spring.factories文件和enableautoconfiguration提一下,那么这个问题就答的八九不离十了。
就像四五年前,我去面试的时候被问到这个问题,spi动态扩展机制这几个词从嘴里一说出来,就把面试官唬的一愣一愣的。可能他们也没见过这么能装逼的,一句话能简简单单说明白,非要拽一个听上去很高大上的词。
话说回来,被唬住的可不止是面试官,其实还有我自己。至于spi扩展究竟是个啥,是怎么实现的,我当时也根本不明白。
不过现在的面试就是这样,对线八股文,要想唬住面试官,就得先唬住自己。
那么我们今天暂且不提spring的spi扩展,先来看看java本身自带的spi扩展机制是怎么一回事。
1、简介spi的全称是service provider interface,翻译过来就是 服务提供者的接口 ,它所实现的其实是一种服务的发现机制。
这么说起来可能还是有点不好理解,我举个例子来类比一下。
在spring项目中,写service层代码前,会约定俗成的会添加一个接口层。然后通过spring中的依赖注入,可以借助@autowired等方式注入这个接口的实现类的实例对象,之后对于service的调用一般也基于接口操作。
简单形容就是这样的:
如图所示,接口、实现类都是由服务提供方提供,我们可以把controller看作服务调用者,调用方只管调用接口就可以了。
虽然也有声音认为,大部分情况下service只有一个实现类,接口层显得有些多余。但是在《head first design patterns》这本书中,大佬们还是建议过:
program to an interface, not an implementation.
没错,就是常说的 要面向接口编程 。至于好处,也不外乎是降低耦合度、方便日后扩展、提高了代码的灵活性和可维护性等等。
在上面这个例子里,这个接口层和其中的方法我们可以称之为 api ,而我们要讨论的spi和它相比,有类似也有差异,还是先看图:
简单来说,就是服务的调用方定义一个接口规范,可以由不同的服务提供者实现。并且,调用方能够通过某种机制来发现服务提供方,并通过接口调用它的能力。
通过对比,我们可以看出它们虽然都有着接口这一层面,但还是有很大的不同:
api中的接口是服务提供者给服务调用者的一个功能列表,而spi中更多强调的是,服务调用者对服务实现的一种约束,服务提供者根据这种约束实现的服务,可以被服务调用者发现。
说白了,java中的spi实现的就是,你按我的接口规范实现服务,我就能通过某种机制为这个接口寻找到这个服务。
这么说起来可能还有些抽象,下面我们举一个例子,类比具体描述一下这个过程。
2、定义接口说起智能家居系统,大家现在都比较熟悉了,只要是相同品牌下的产品,连上wifi就能够通过手机app控制了,非常方便。
虽然产品不断更新换代,型号更新层出不穷,但是同种家电在app上操作起来,功能一般都是一样的。就拿空调来说,我们在app上操作起来一般也就三个主要功能: 开关 , 选模式 , 调节温度 。
假设我现在在客厅、卧室、书房安装了3款不同型号的空调,并把它们都接入到了我app中,那么之后的操作都是相同的几个按键,简单粗暴。
思考一下,无论是开关还是调温,都是通过app去调用设备的接口罢了,那么如果不同型号的空调各写各的接口,后端app在开发的时候光对接接口都麻烦的要死。
解决方法也很简单,我先定义一套接口规范,不管你以后什么型号的空调,都按我的规范来实现接口。以后只要我能发现你的设备,那么都可以按相同的方法来调用接口。
那么下面就先来定义这么一套接口规范,如果你以后想要接入智能家居系统,那么就要遵循这个规范来开发接口。
新建一个项目作为标准,就叫aircondition-standard好了,然后创建一个接口。除了3个操作以外,我们再添加一个获取空调型号的方法。
public interface iaircondition { // 获取型号 string gettype(); // 开关 void turnonoff(); // 调节温度 void adjusttemperature(int temperature); // 模式变更 void changemodel(int modelid);}这个接口后面要给服务的实现方来使用,用maven把它打成jar包:
mvn clean install之后服务提供者在项目中就可以引入这个jar包了,有了这套规范,就保证了产品后期不管怎么更新换代,都能接入到系统来。
3、服务实现制定并发布完规则后,挂式空调作为第一个服务提供者就来了,新建一个项目aircondition-hanging-type,并引入刚才打好的jar包:
com.cn.hydra aircondition-standard 1.0-snapshot创建服务类,并实现前面定义的接口:
public class hangingtypeaircondition implements iaircondition{ public string gettype() { return hangingtype; } public void turnonoff() { system.out.println(挂式空调开关); } public void adjusttemperature(int i) { system.out.println(挂式空调调节温度); } public void changemodel(int i) { system.out.println(挂式空调更换模式); }}在项目的resources的目录下,创建meta-inf/services目录,然后以前面定义的接口名com.cn.hydra.iaircondition创建文件,并在文件中写入实现类的全限定名。
com.cn.hydra.hangingtypeaircondition整个项目结构非常简单:
这样,一个服务方的简单实现就搞定了,用maven打成jar包,之后就可以提供给调用方使用了。
同理,我们可以再创建一个立式空调的项目aircondition-vertical-type,也只创建一个服务类:
public class verticaltypeaircondition implements iaircondition{ public string gettype() { return verticaltype; } public void turnonoff() { system.out.println(立式空调开关); } public void adjusttemperature(int i) { system.out.println(立式空调调节温度); } public void changemodel(int i) { system.out.println(立式空调更换模式); }}还是按上面的命名规则,创建一个配置文件:
com.cn.hydra.verticaltypeaircondition同样,打成jar包就完事了,至于服务调用者如何去发现和调用这两个服务,下面详细再说。
下一代导弹驱动系统的无刷直流电机概要
vivo冲刺销量,iQOO Neo3跌至2549元
特征频率,特征频率是什么意思
毕设早鸟买料优惠!【限时反馈+分享有礼】
中兴通讯发布新5G+Wi-Fi6室内CPE产品
Java中的SPI动态扩展(上)
单片机多CPU系统设计的详细资料概述
W600大屏幕熔炼测温仪的特点及应用范围
德赛西威最新一代智能座舱G7PH平台为用户打造极致体验
影响蓝牙无线传输范围的关键因素是什么
数字资产钱包如何选择合适的种类
今年一季度苹果iOS美国市场份额达44%
华为轮值董事长徐直军就网络监控、代码重构等5G部署敏感回答英国媒体团问
单相异步电机调速方法及调速原理
Google在印度的主要投资
CPU和显卡到底哪个更重要
华为云计算认证
小行星“法厄同”将在圣诞节前后掠过地球:最近约1000万公里
美东海岸供油“大动脉”断线,有地区现恐慌囤油
CITE 2014:中国取代美国成为全球最大消费电子市场