美文网首页
框架必备的SPI扩展机制

框架必备的SPI扩展机制

作者: 十毛tenmao | 来源:发表于2019-05-09 22:30 被阅读0次

    很多框架中,为了实现更好的扩展机制,都是用了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生成后会被垃圾回收。

    参考

    相关文章

      网友评论

          本文标题:框架必备的SPI扩展机制

          本文链接:https://www.haomeiwen.com/subject/lkkuoqtx.html