Java SPI机制
来源:互联网 发布:电脑网络id按钮在哪 编辑:程序博客网 时间:2024/05/16 11:36
SPI机制简述
SPI的全称是Service Provider Interface。简单来说,SPI机制提供了一个表达接口和其具体实现类之间的绑定关系的方案。具体是在JAR包的”META-INF/services/”目录下建立一个文件,文件名是接口的全限定名,文件的内容可以有多行,每行都是该接口对应的具体实现类的全限定名。
SPI可以理解是为接口寻找服务实现类。现在公司的系统都是进行了模块的划分,系统抽象为多个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。于是就有了SPI这种服务发现机制。
SPI的全名是Service Provider Interface .SPI机制提供了
jdbc中spi机制
在java中,Java.sql.Driver接口是Java对外公开的一个加载驱动接口,Java并未实现,至于实现这个接口由各个Jdbc厂商去实现就行了,好处是解藕,使得更具有灵活性,当然这也是面向对象的好处之一。真正的实现是不同提供商提供的。
Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select * from Users");
Class.forName(“com.mysql.jdbc.Driver”);这里虽是加载mysql的driver,但是无论是oracle还是其它的jdbc驱动包,它们的原理都是spi机制。
首先看java.sql.driver
package java.sql; import java.util.logging.Logger; public interface Driver { boolean acceptsURL(String url) throws SQLException; DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info) throws SQLException; int getMinorVersion(); boolean jdbcCompliant(); public Logger getParentLogger() throws SQLFeatureNotSupportedException; }
这个类是一个接口类, 在整个JDK包中都没有它的实现类,它的实现要由各个jdbc的开发产商去实现,但是我们发现DriverManager这个类中还是有去加载Driver类,那它是怎么发现其它开发商实现的Driver类?
再来看看DriverManager
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
com.mysql.jdbc.Driver这样就实现了在我们程序运行时引入mysql-connector-java-.jar这个包。然后在JDK源码中,当我们调用到
DriverManager.getConnection的方法,就会将程序中使用到的Driver接口类用mysql驱动包的Driver实现类来使用
这一句就是真实的发现driver类的实现类。
在mysql-connector-java-.jar包下面META-INF.services包下有个java.sql.Driver文件打开文件有下面两行
这里将driver封成一个driverinfo对象,然后在DriverManager 这个类加载时就初始化一次,那初始化它做什么呢?其实就是其发现driver类的实现类,并加载到当前类中。注意看loadInitialDrivers方法。
这样做有什么好处呢?
1. 不用在JDK里实现Driver实现类的硬编码,然后每次使用JDK里的DriverManager 类时,都会自动去发现Driver类的实现类,并根据这个实现类来做数据库连接。
2. 可以满足不同的产商实现各不相同,但对外暴露一样的接口。使用方只要按照JDK的标准方法来调用即可,即实现了接口的可拔插
实例
下面以一个具体的例子来说明一下ServiceLoader的具体使用,类似Hadoop FileSystem中的实现。
首先定义一个接口,具体如下:
public interface IService { public String sayHello(); public String getScheme(); }
该接口有两个子类,分别为HDFSService和LocalService:
public class HDFSService implements IService { @Override public String sayHello() { return "Hello HDFS!!"; } @Override public String getScheme() { return "hdfs"; } }
public class LocalService implements IService { @Override public String sayHello() { return "Hello Local!!"; } @Override public String getScheme() { return "local"; } }
需要在META-INF/services下以IService这个类的全名来新建立一个文件,文件中的内容为两个实现类的全名,如下:
org.hadoop.java.HDFSService org.hadoop.java.LocalService
所有的实现和配置都已经完成,下面写一个测试类来看一下结果:
public class ServiceLoaderTest { /** * @param args */ public static void main(String[] args) { //need to define related class full name in /META-INF/services/.... ServiceLoader<IService> serviceLoader = ServiceLoader .load(IService.class); for (IService service : serviceLoader) { System.out.println(service.getScheme()+"="+service.sayHello()); } } }
具体的输出来如下:
hdfs=Hello HDFS!! local=Hello Local!!
可以看到ServiceLoader可以根据IService把定义的两个实现类找出来,返回一个ServiceLoader的实现,而ServiceLoader实现了Iterable接口,所以可以通过ServiceLoader来遍历所有在配置文件中定义的类的实例
- Java的SPI机制
- java spi 机制
- java中的SPI机制
- Java的SPI机制
- Java SPI机制
- ServiceLoader : JAVA SPI 机制
- Java spi机制
- Java SPI机制
- Java spi机制浅谈
- java中的SPI机制
- Java SPI机制
- Java SPI机制
- Java SPI机制简介
- Java spi机制浅谈
- Java的SPI机制
- Java SPI机制实践
- Java spi机制浅谈
- java中的SPI机制
- sql注入
- 【Linxu内核设计与实现】-第1章 Linux内核简介
- [反思]NOIP2017棋盘
- 序列化学习
- textarea 单击输入时标点不在第一个字符的位置
- Java SPI机制
- Ubuntu系统安装碰到的一些问题
- 矩形
- 堆
- 6.4
- 【JS】关于表单提交前验证的方法和可能遇到的问题总结
- leetcode题解-143. Reorder List
- 最短路模板
- 58. Length of Last Word