• Apache Dubbo的@SPI接口应用


    记录:472

    场景:使用Apache Dubbo的@SPI接口加载实现类搭建框架。

    版本:JDK 1.8,dubbo-common-3.0.0。

    SPI全称Service Provider Interface。

    1.基础

    1.1引用依赖

    1. <dependency>
    2. <groupId>org.apache.dubbogroupId>
    3. <artifactId>dubbo-commonartifactId>
    4. <version>3.0.0version>
    5. dependency>

    1.2应用

    (1)使用@SPI注解作用在自定义接口com.hub.example.pf.adapter.IPfDataAdapter。

    (2)业务类TCityAdapterImpl、TProvinceAdapterImpl等实现接口IPfDataAdapter。

    (3)在..\src\main\resources目录下,新建\META-INF\services目录

    (4)在\META-INF\services目录新建配置文件:com.hub.example.pf.adapter.IPfDataAdapter,文件名称就是@SPI注解作用的接口全路径名称。

    (5)在\META-INF\services\com.hub.example.pf.adapter.IPfDataAdapter配置文件中添加入下内容(key=value键值对):

    1. t_province=com.hub.example.process.adapter.TProvinceAdapterImpl
    2. t_city=com.hub.example.process.adapter.TCityAdapterImpl

    (6)根据配置文件中key名称和接口名称获取实现类,如下:

    IPfDataAdapter var= ExtensionLoader.getExtensionLoader(IPfDataAdapter.class).getExtension(tableName);

    1.3逻辑

    Apache Dubbo框架对使用@SPI注解接口,会在..\src\main\resources\META-INF\services目录下扫描配置并加载。

    2.示例场景

    (1)从某数据源(比如数据库)中读取数据存放在:Map data。

    (2)组装成Tuple3> in数据格式,其中Tuple3第一个参数数:表名称,第二参数:指定的字段名称,第三个参数就是数据。

    (3)使用计算框架com.hub.example.pf.function.PfDataMapFunction计算业务

    输入:Tuple3> in;

    输出:Tuple3> out;

    (4)把Tuple3> out传递给下游处理。比如数据写入到HBase等目的端。

    3.示例代码

    3.1接口和抽象类

    (1)接口IPfDataAdapter

    全称:com.hub.example.pf.adapter.IPfDataAdapter

    代码:

    1. @SPI
    2. public interface IPfDataAdapter {
    3. Tuple3> getPfData(Map value);
    4. }

    (2)抽象类

    全称:com.hub.example.pf.adapter.PfDataAdapterAbstract

    代码:

    1. public abstract class PfDataAdapterAbstract implements IPfDataAdapter {
    2. public PfDataAdapterAbstract() {
    3. }
    4. public Tuple3> getPfData(Map data) {
    5. try {
    6. Map result = new HashMap(data.size());
    7. for (Map.Entry entry : data.entrySet()) {
    8. if (entry.getValue() != null) {
    9. result.put(entry.getKey(), entry.getValue().toString());
    10. }
    11. }
    12. return new Tuple3(this.getTableName(), this.getRowKeyColumns(), result);
    13. } catch (Exception e) {
    14. return new Tuple3(null, null, new HashMap<>());
    15. }
    16. }
    17. public abstract String getDataType();
    18. public String getTableName() {
    19. return TableConfig.getTableName(this.getDataType());
    20. }
    21. public String getRowKeyColumns() {
    22. return TableConfig.getRowKeyColumns(this.getDataType());
    23. }
    24. }

    3.2计算框架

    全称:com.hub.example.pf.function.PfDataMapFunction

    代码:

    1. public class PfDataMapFunction {
    2. public PfDataMapFunction() {
    3. }
    4. public Tuple3> map(Tuple3> data) {
    5. try {
    6. String tableName = (String) data.f0;
    7. IPfDataAdapter dataAdapter = ExtensionLoader.getExtensionLoader(IPfDataAdapter.class).getExtension(tableName);
    8. if (dataAdapter == null) {
    9. return new Tuple3();
    10. } else {
    11. return dataAdapter.getPfData((Map) data.f2);
    12. }
    13. } catch (Exception e) {
    14. e.printStackTrace();
    15. return new Tuple3();
    16. }
    17. }
    18. }

    3.3业务类

    (1)业务类TProvinceAdapterImpl对应表:t_province

    全称:com.hub.example.process.adapter.TProvinceAdapterImpl

    代码:

    1. public class TProvinceAdapterImpl extends PfDataAdapterAbstract {
    2. public TProvinceAdapterImpl() {
    3. }
    4. @Override
    5. public String getDataType() {
    6. return "T_PROVINCE";
    7. }
    8. public Tuple3> getPfData(Map data) {
    9. if (data.get("PROVINCE_ID") == null) {
    10. return new Tuple3();
    11. }
    12. return super.getPfData(data);
    13. }
    14. }

    (2)业务类TCityAdapterImpl对应表:t_city

    全称:com.hub.example.process.adapter.TCityAdapterImpl

    代码:

    1. public class TCityAdapterImpl extends PfDataAdapterAbstract {
    2. @Override
    3. public String getDataType() {
    4. return "T_CITY";
    5. }
    6. public Tuple3> getPfData(Map data) {
    7. if (data.get("CITY_ID") == null) {
    8. return new Tuple3();
    9. }
    10. return super.getPfData(data);
    11. }
    12. }

    3.4配置文件

    (1)配置目录..\META-INF\services

    目录:..\src\main\resources\META-INF\services

    (2)配置文件com.hub.example.pf.adapter.IPfDataAdapter

    文件名:com.hub.example.pf.adapter.IPfDataAdapter

    文件内容:

    1. t_province=com.hub.example.process.adapter.TProvinceAdapterImpl
    2. t_city=com.hub.example.process.adapter.TCityAdapterImpl

    3.5配置类

    全称:com.hub.example.config.TableConfig

    代码:

    1. public class TableConfig {
    2. private static ConcurrentHashMap tableConfig = new ConcurrentHashMap<>();
    3. static {
    4. tableConfig.put("TABLE:T_PROVINCE", "HUB:T_PROVINCE");
    5. tableConfig.put("ROW_KEY:T_PROVINCE", "V_DATA_DATE,PROVINCE_ID");
    6. tableConfig.put("TABLE:T_CITY", "HUB:T_CITY");
    7. tableConfig.put("ROW_KEY:T_CITY", "V_DATA_DATE,CITY_ID");
    8. }
    9. public static String getTableName(String tableName) {
    10. return tableConfig.get("TABLE:" + tableName.toUpperCase());
    11. }
    12. public static String getRowKeyColumns(String tableName) {
    13. return tableConfig.get("ROW_KEY:" + tableName.toUpperCase());
    14. }
    15. }

    3.6实体类

    全称:com.hub.example.api.Tuple3

    代码:

    1. public class Tuple3 implements Serializable {
    2. private static final long serialVersionUID = 1L;
    3. public T0 f0;
    4. public T1 f1;
    5. public T2 f2;
    6. public Tuple3() {
    7. }
    8. public Tuple3(T0 f0, T1 f1, T2 f2) {
    9. this.f0 = f0;
    10. this.f1 = f1;
    11. this.f2 = f2;
    12. }
    13. public static String arrayAwareToString(Object o) {
    14. String arrayString = Arrays.deepToString(new Object[]{o});
    15. return arrayString.substring(1, arrayString.length() - 1);
    16. }
    17. public String toString() {
    18. return "(" + arrayAwareToString(this.f0) + ";" + arrayAwareToString(this.f1) + ";" + arrayAwareToString(this.f2) + ")";
    19. }
    20. }

    4.示例测试

    全称:com.hub.example.process.ExampleApplicationSPI

    代码:

    1. public class ExampleApplicationSPI {
    2. public static void main(String[] args) throws Exception {
    3. PfDataMapFunction dataPfMapFunction = new PfDataMapFunction();
    4. //操作t_province
    5. String table01 = "t_province";
    6. Map data01 = getTProvince();
    7. Tuple3> in01 = new Tuple3(table01, data01.get("PROVINCE_ID"), data01);
    8. Tuple3> out01 = dataPfMapFunction.map(in01);
    9. System.out.println("操作表t_province后数据: " + out01.toString());
    10. //操作t_city
    11. String table02 = "t_city";
    12. Map data02 = getTCity();
    13. Tuple3> in02 = new Tuple3(table02, data02.get("CITY_ID"), data02);
    14. Tuple3> out02 = dataPfMapFunction.map(in02);
    15. System.out.println("操作表t_city后数据: " + out02.toString());
    16. }
    17. public static Map getTProvince() {
    18. Map dataMap = new HashMap<>();
    19. dataMap.put("PROVINCE_ID", 33001694333578181L);
    20. dataMap.put("V_DATA_DATE", "20230910");
    21. dataMap.put("PROVINCE_NAME", "浙江");
    22. dataMap.put("GROSS", 7.77D);
    23. return dataMap;
    24. }
    25. public static Map getTCity() {
    26. Map dataMap = new HashMap<>();
    27. dataMap.put("CITY_ID", 33011694333578181L);
    28. dataMap.put("V_DATA_DATE", "20230911");
    29. dataMap.put("CITY_NAME", "杭州");
    30. dataMap.put("GROSS", 1.88D);
    31. return dataMap;
    32. }
    33. }

    以上,感谢。

    2023年9月10日

  • 相关阅读:
    全面解析:Foxit Reader支持的操作系统及其特性
    定位new运算符
    React常见的一些坑
    【latex】参考文献bbl错误,Package inputenc Error,Misplaced alignment
    会话控制学习
    内存虚拟化技术-POD和Ballooning
    Win10找不到便签怎么办 Win10找不到便签解决方法
    React Native for Arcgis 地图开发 GraphicCtrl (十三)
    【Go语言】Go语言中的字典
    单链表经典例题
  • 原文地址:https://blog.csdn.net/zhangbeizhen18/article/details/132796704