Java SPI及Demo

首先交代下背景,何为Java SPI?
SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。

为什么需要SPI?

我们的现代系统越来越庞大,如果设计架构有问题,就可能牵一发而动全身,在面向对象中我们推荐基于接口编程,模块之间基于接口编程,这样的好处显而易见,不在代码中进行硬编码,不同的实现者按照接口规范实现自己内部操作,然后在使用的时候再根据 SPI 的规范去获取对应的服务提供者的服务实现。通过 SPI 服务加载机制进行服务的注册和发现,可以有效的避免在代码中将服务提供者写死。从而可以基于接口编程,实现模块间的解耦。

SPI机制约定:

1.在 META-INF/services/ 目录中创建以接口全限定名命名的文件,该文件内容为API具体实 现类的全限定名

2.使用 ServiceLoader 类动态加载 META-INF 中的实现类

3.如 SPI 的实现类为 Jar 则需要放在主程序 ClassPath 中

4.API 具体实现类必须有一个不带参数的构造方法

如图:

现在已经被使用的案例:

  1. common-logging Apache最早提供的日志的门面接口。只有接口,没有实现。具体方 案由各提供商实现, 发现日志提供商是通过扫描 META- INF/services/org.apache.commons.logging.LogFactory配置文件,通过读取该文 件的内容 找到日志提工商实现类。只要我们的日志实现里包含了这个文件,并在文件里 制定LogFactory工厂接口的实现类即可。
  2. JDBC jdbc4.0以前, 开发人员还需要基于Class.forName("xxx")的方式来装载驱动。 创建连接: DriverManage.getConnection()中,有Connection con = aDriver.driver.connect(url, info); driver成员变量,是java.sql.Driver接口,Java对外公开的一个加载驱动接口,Java并未实现,至于实现这个接口由各个Jdbc厂商去实现。 如MySQL,mysql-connector-java-5.1.38.jar包下面META-INF.services包下有个java.sql.Driver文件打开文件有下面两行 com.mysql.jdbc.Driver com.mysql.fabric.jdbc.FabricMySQLDriver
    示例Demo:

创建maven项目

目录如下:

代码

OrderService.java

package com.demo.spi.service;

public interface OrderService {
    int getOrderCountById(int id);
}

CustomerOrderServiceImpl.java

package com.demo.spi.impl;

import com.demo.spi.service.OrderService;

public class CustomerOrderServiceImpl implements OrderService {

    public int getOrderCountById(int id) {
        System.out.println("cutomer order count is 10");
        return 10;
    }

}

AgencyOrderServiceImpl.java

package com.demo.spi.impl;

import com.demo.spi.service.OrderService;

public class AgencyOrderServiceImpl implements OrderService {

    public int getOrderCountById(int id) {
        System.out.println("agency order count is 20");
        return 20;
    }

}

META-INF下文件名:com.demo.spi.service.OrderService,文件内容:

com.demo.spi.impl.AgencyOrderServiceImpl
com.demo.spi.impl.CustomerOrderServiceImpl复制代码

4.新建测试项目java project

运行main方法之前我们需要将第一个项目进行打包 jar 依赖到第二个java 项目中来,完成之后点击run,可以看到打印出了,我们在项目1 中的两个serviceImpl方法的输出,也就是说ServiceLoader 动态的通过jar中的配置找到了 项目1中的实现类并且把他记载到了内存中,我们就可以直接调用项目1中提供的两个实现类,并且正确输出。

最后

顺便在此给大家推荐一个Java方面的交流学习群:957734884,里面会分享一些高级面试题,还有资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系,主要针对Java开发人员提升自己,突破瓶颈,相信你来学习,会有提升和收获。在这个群里会有你需要的内容 朋友们请抓紧时间加入进来吧

原文地址:https://blog.51cto.com/14207399/2353202

时间: 2024-08-26 15:24:26

Java SPI及Demo的相关文章

Java SPI 实例

SPI 全称为 Service Provider Interface,是一种服务发现机制.SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类.这样可以在运行时,动态为接口替换实现类. 这里简单写一个例子示意 创建DemoService接口 如下 1 package com.demo; 2 3 /** 4 * @author chaixg 5 * 2019/1/25 6 */ 7 public interface DemoService { 8 9 void

Dubbo 扩展点加载机制:从 Java SPI 到 Dubbo SPI

SPI 全称为 Service Provider Interface,是一种服务发现机制.当程序运行调用接口时,会根据配置文件或默认规则信息加载对应的实现类.所以在程序中并没有直接指定使用接口的哪个实现,而是在外部进行装配. 要想了解 Dubbo 的设计与实现,其中 Dubbo SPI 加载机制是必须了解的,在 Dubbo 中有大量功能的实现都是基于 Dubbo SPI 实现解耦,同时也使得 Dubbo 获得如此好的可扩展性. Java SPI 通过完成一个 Java SPI 的操作来了解它的机

Exception in thread "main" java.lang.NoClassDefFoundError: Demo (wrong name: com/zhangyun/Demo)解决办法

介绍一个Java初学者可能会遇到的问题 首先,创建一个类,如下: 文件名:Demo.java package com.zhangyun; public class Demo { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("Hello World!"); } } 然后我找到对应在磁盘的位置,如下: E

【JAVA】使用Java SPI ServiceLoader进行Java应用插件模块化开发

背景:在进行业务定制时需要考虑不同接口的服务实现,每个局点所要求的接口大体都不一致,要求接口服务能够插件化方式提供: 方案分析: 1)采用OSGI框架进行开发,但是考虑到OSGI的框架太重,需要引入的东西比较多,放弃了该方案: 2)采用Java class loader动态加载外部jar机制,动态加载定制的接口服务类,这种方式实现比较复杂,需要完成指定接口服务类的文件加载,同时需要能查找到所有接口服务类,作为备选方案: 3)使用java service provider interface(SP

java mail发送邮件demo 代码

java mail发送邮件demo,引入mail.jar,运行测试发送ok[代码][Java]代码     01import java.util.Date;02import java.util.Properties;0304import javax.mail.Authenticator;05import javax.mail.Message;06import javax.mail.MessagingException;07import javax.mail.PasswordAuthenticat

JAVA长连接demo

http://blog.csdn.net/caomiao2006/article/details/38830475 JAVA长连接demo 2014-08-25 23:20 4767人阅读 评论(2) 收藏 举报  分类: JAVA(161)  [java] view plain copy package houlei.csdn.keepalive; import java.io.Serializable; import java.text.SimpleDateFormat; import ja

Java反射机制demo(四)—获取一个类的父类和实现的接口

Java反射机制demo(四)—获取一个类的父类和实现的接口 1,Java反射机制得到一个类的父类 使用Class类中的getSuperClass()方法能够得到一个类的父类 如果此 Class 表示 Object 类.一个接口.一个基本类型或 void,则返回 null.如果此对象表示一个数组类,则返回表示该 Object 类的 Class 对象. 测试代码: package com.aaron.reflect; public class Demo4 { public static void

Java SPI机制和使用示例

JAVA SPI 简介 SPI 是 Java 提供的一种服务加载方式,全名为 Service Provider Interface.根据 Java 的 SPI 规范,我们可以定义一个服务接口,具体的实现由对应的实现者去提供,即服务提供者.然后在使用的时候再根据 SPI 的规范去获取对应的服务提供者的服务实现.通过 SPI 服务加载机制进行服务的注册和发现,可以有效的避免在代码中将服务提供者写死.从而可以基于接口编程,实现模块间的解耦. SPI 机制的约定 1 在 META-INF/service

java反序列化原理-Demo(一)

java反序列化原理-Demo(一) 0x00 什么是java序列化和反序列? Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存.文件.数据库中,ObjectOutputStream类的 writeObject() 方法可以实现序列化.Java 反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() 方法用于反序列化. 0x01 java反序列漏洞原理分析 首先先定义一个user类需继承Serializabl