`
rensanning
  • 浏览: 3513969 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
Efef1dba-f7dd-3931-8a61-8e1c76c3e39f
使用Titanium Mo...
浏览量:37478
Bbab2146-6e1d-3c50-acd6-c8bae29e307d
Cordova 3.x入门...
浏览量:604304
C08766e7-8a33-3f9b-9155-654af05c3484
常用Java开源Libra...
浏览量:678049
77063fb3-0ee7-3bfa-9c72-2a0234ebf83e
搭建 CentOS 6 服...
浏览量:87250
E40e5e76-1f3b-398e-b6a6-dc9cfbb38156
Spring Boot 入...
浏览量:399811
Abe39461-b089-344f-99fa-cdfbddea0e18
基于Spring Secu...
浏览量:69066
66a41a70-fdf0-3dc9-aa31-19b7e8b24672
MQTT入门
浏览量:90468
社区版块
存档分类
最新评论

关于Java SPI

    博客分类:
  • Java
 
阅读更多
SPI:Service Provider Interface

自身只定义接口,通过其他jar来提供实现,从而可以实现jar包替换后即可执行,实现IoC,可用于plugins/modules。

(1)Java Service Loader

JDK 6开始提供java.util.ServiceLoader

https://docs.oracle.com/javase/tutorial/ext/basics/spi.html
https://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html

定义实现类
META-INF/services/[InterfaceFQCN]

比如:
META-INF/services/com.rensanning.spi.Sample
引用
com.rensanning.spi.SampleImpl1 # comment1
com.rensanning.spi.SampleImpl2 # comment2


-可以定义多行,一行一个实现(多个实现具体如何用是在程序内部控制的)
-#号开头的是注释
-必须UTF-8编码(避免使用非英语字符)

获取实现类
ServiceLoader<Sample> loader = ServiceLoader.load(Sample.class);
for (Sample provider: loader) {
    // ...
}


-默认采用的是当前线程的类加载器(Thread Context Classloader)
-可以自己指定类加载器:ServiceLoader.load(Sample.class, ClassLoader.getSystemClassLoader());
-ServiceLoader只能通过无参构造函数对服务实例
-ServiceLoader返回一个Iterator对象对服务实例懒加载,只有调用next()方法时才会实例化下一个服务实例

集成Spring
@Configuration
public class ServiceConfiguration {
    @Bean
    public ServiceListFactoryBean serviceListFactoryBean() {
        ServiceListFactoryBean serviceListFactoryBean = new ServiceListFactoryBean();
        serviceListFactoryBean.setServiceType(Sample.class);
        return serviceListFactoryBean;
    }
}

Object object = serviceListFactoryBean.getObject();


JDK1.5通过sun.misc.Service(未公开的API)来加载。

Iterator<Sample> i = Service.providers(Sample.class);
while (i.hasNext()) {
  Sample s = i.next();
  // ...
}


-其实META-INF/services是JDK 1.3开始就有的“Java Extension Mechanism”

最典型的2个应用:JDBC、Logger

JDBC

JDBC4 定义了接口java.sql.Driver,具体实现可以是MySQL、PostgreSQL等
mysql-connector-java-5.1.22-bin.jar/META-INF/services/java.sql.Driver
引用
com.mysql.jdbc.Driver

postgresql-9.4-1201-jdbc4.jar/META-INF/services/java.sql.Driver
引用
org.postgresql.Driver


java.sql.DriverManager在初始化的时候会主动加载这些驱动类,不需要Class.forName()。
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);


Logger

可以通过实现来切换JUL,Logback, Log4J等

SLF4J 定义了接口org.slf4j.Logger,但还不支持SPI,仍采用的是StaticLoggerBinder来实现的。
https://jira.qos.ch/browse/SLF4J-227

JBoss Logging:META-INF/services/org.jboss.logging.LoggerProvider
common-logging:META-INF/services/org.apache.commons.logging.LogFactory

OSGi 和 SPI之间还有些纠纷,具体可以看看这里:
http://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html

(2)Spring Factories Loader
Spring自己实现了一个类似于属性文件的配置文件:META-INF/spring.factories

http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/io/support/SpringFactoriesLoader.html
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/serviceloader/package-summary.html

比如:
spring-boot-autoconfigure-1.5.2.RELEASE.jar/META-INF/spring.factories
引用
# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider


org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders
List<TemplateAvailabilityProvider> providers = SpringFactoriesLoader.loadFactories(TemplateAvailabilityProvider.class, classLoader);


参考:
https://dzone.com/articles/java-service-loader-vs-spring-factories-loader
http://stackoverflow.com/questions/2954372/difference-between-spi-and-api
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics