框架必备的SPI扩展机制

很多框架中,为了实现更好的扩展机制,都是用了JDK支持的SPI机制,本文简单介绍了一下,并提供了快速实现的示例

SPI

Java SPI(Service Provider Interface)是一种JDK支持的扩展机制,可以为某个接口寻找服务实现的机制,有点类似于IOC的思想,将装配的控制权移到了程序之外。

Java SPI

SPI常用场景

  • 数据库驱动加载

MySQL Driver

  • Servlet API中的javax.servlet.ServletContainerInitializer
  • Dubbo中的类SPI机制,实现功能点的扩展(Dubbo可扩展机制实战

接口定义方

类似于JDK中的java.sql.Driver

  • 接口
public interface Scorer {
    double score(String first, String second);
}
  • 管理器
public class ScorerManager {
    private static final Map<String, Scorer> SCORER_MAP = new HashMap<>(16);

    static {
        loadInitialScorers();
        System.out.println("Scorer Manager initialized");
    }

    public static void registerScore(Scorer scorer) {
        SCORER_MAP.putIfAbsent(scorer.getClass().getName(), scorer);
    }

    public static Scorer getScore(String scoreName) {
        Scorer scorer = SCORER_MAP.get(scoreName);
        if (scorer == null) {
            throw new RuntimeException("cannot not find score with name:" + scoreName);
        }
        return scorer;
    }

    private static void loadInitialScorers() {
        ServiceLoader<Scorer> serviceLoader = ServiceLoader.load(Scorer.class);
        for (Scorer scorer : serviceLoader) {
            //这里可以什么都不做,只是出发实现类的构造函数和静态模块
            //其实也可以在这里完成注册,这样的话各个实现类会更加简单。不过在实现类中实现注册,会更加灵活,因为实现类在注册之前也许还需要做一些初始化的工作
        }
    }
}

接口实现方

类似于mysql中的com.mysq.Drivercom.mysql.cj.jdbc.Driver, h2中的org.h2.Driver

  • 实现类
public class BarScorer implements Scorer {
    static {
        ScorerManager.registerScore(new BarScorer());
        System.out.println("BarScorer initialized");
    }

    @Override
    public double score(String first, String second) {
        return 0;
    }
}
  • META-INF/services/com.tenmao.Scorer文件
com.tenmao.BarScorer

接口使用方

  • 用户应用程序
public static void main(String[] args) {
    Scorer score = ScorerManager.getScore("com.tenmao.BarScorer");
    double scoreOne = score.score("1", "1");
    System.out.println(scoreOne);
}

注意事项

  • 接口实现类必须包含无参构造函数(默认就有)
  • 一般在XxxManager中不会注册实现类,而是交由实现类中静态模块完成。这样会存在一个问题,一个实现类会生成至少两个对象,其中一个对象被ServiceLoader生成后会被垃圾回收。

参考

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券