概述
SPI-服务扩展点可以使得项目结构更加解耦,比如我司在支付方式模块中,全平台都可以使用在线支付,单由于业务场景要求,不同的业务实例会有定制化的支付方式,如非国有性质的采购人可以申请使用账期支付等。原先的技术实现是有订单模块代码中根据业务实例写死一堆的if-else业务实现,随着接入业务的增加,代码变得越来越臃肿和不可维护。为了该模块更具扩展性和易维护性,我们希望通过由订单中心提供支付方式SPI扩展接口,不同的业务线可以更灵活的配置各自的支付方式。
在一个项目中定义一个扩展接口,然后写不同的实现,并在项目中的META-INF/services路径下写好扩展点实现路径,然后项目在启动的时候回加载这些实现;现在的问题是如何在不同的项目中使用SPI,也就是项目A定义了一个SPI接口,项目B和项目C在实现了其接口后,项目A怎么找到这些实现?这里大概有两种方式:
- 通过JAR包,项目B和项目C实现项目A的SPI接口后,打包成JAR后放到项目A中;
- 通过dubbo注册中心机制,项目B和项目C在实现项目A的SPI接口后,向注册中心注册其实现,然后项目A再通过注册中心获取具体实现类和方法;
由于小菜不想每次修改实现或有新接入方时都要重新打包,并复制给SPI提供方,来来回回,不仅繁琐,而且中间也容易出错。所以这里主要探讨第二种方案是怎么做的。
注解和反射技术是做这件事的一大利器。
1、首先,应该定义一个注解,用于标识那些接口是SPI接口;凡是接口有该注解的,我们单独先把它拎出来;
import java.lang.annotation.*;
/**
* 标记一个 dubbo 接口是否为 SPI 接口
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPIInterface {
/**
* SPI所属应用
*
* @return
*/
String appName();
/**
* SPI所属的功能
*
* @return
*/
String function();
/**
* SPI描述
*
* @return
*/
String desc();
}
2、识别了那些事SPI接口,我们自然会想到该如何识别那些类是SPI接口的实现类;同理:
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
/**
* 标记一个实现类为SPI的扩展实现
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface SPIProvider {
/**
* SPI实现类的描述
*
* @return
*/
String desc();
/**
* SPI服务提供方式:jar or rpc
*
* @return
*/
SPIProviderMode providerMode() default SPIProviderMode.JAR;
/**
* SPI分组标签
*
* @return
*/
String label();
/**
* 是否为默认的SPI实现
*
* @return
*/
boolean defaultProvider() default false;
}
凡是实现类有该注解的,我们会把它看做是某一SPI接口的实现类;
3、假设项目B和项目C实现项目A的SPI接口,实现完之后,我们希望该实现类能够已dubbo服务的形式上传到注册中心;
4、项目A通过注册中心找到对应的服务类,具体由SPIProvider的label标签区分不同的业务线实现;
最后
以上就是健康毛豆为你收集整理的如何跨项目使用SPI扩展点的全部内容,希望文章能够帮你解决如何跨项目使用SPI扩展点所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复