精华内容
下载资源
问答
  • ServiceLoader

    2019-10-17 14:18:28
    ServiceLoader是SPI(Service Provider Interface)中的服务类加载的核心类 2.破坏双亲 SPI 的接口由 Java 核心库来提供,而这些 SPI 的实现代码则是作为 Java 应用所依赖的 jar 包被包含进类路径(CLASSPATH)里。...

    1.定义

     ServiceLoader是SPI(Service Provider Interface)中的服务类加载的核心类

    2.破坏双亲

    SPI 的接口由 Java 核心库来提供,而这些 SPI 的实现代码则是作为 Java 应用所依赖的 jar 包被包含进类路径(CLASSPATH)里。SPI接口中的代码经常需要加载具体的实现类。那么问题来了,SPI的接口是Java核心库的一部分,是由引导类加载器来加载的;SPI的实现类是由系统类加载器来加载的。引导类加载器是无法找到 SPI 的实现类的,因为依照双亲委派模型,BootstrapClassloader无法委派AppClassLoader来加载类
    线程上下文类加载器破坏了双亲委派模型,可以在执行线程中抛弃双亲委派加载链模式,使程序可以逆向使用类加载器

    1. 如果不想不破坏双亲委派模型,只要去重写findClass方法
    2. 如果想要去破坏双亲委派模型,需要去重写loadClass方法

    3.实例ServiceLoder

    为什么这么搞呢,我觉得就是插拔式的,用就加上不用就不用,对代码一点侵入都没有

     

    创建接口

    public interface LoaderInterface {
    	 void  interfaceTest();
    }

    两个实现类 

    public class ImpTest1 implements LoaderInterface{
    
    	@Override
    	public void interfaceTest() {
    		System.out.println("我是 1");
    	}
    	
    }
    public class ImpTest1 implements LoaderInterface{
    
    	@Override
    	public void interfaceTest() {
    		System.out.println("我是 1");
    	}
    	
    }

    指定实现类

    META-INF/services目录下建立一个文本文件,文件名字为接口完全限定名,内容为实现类的完全限定名

     

     使用main方法调用

    public class TestServiceLoader {
    	public static void main(String[] args) {
    		ServiceLoader<LoaderInterface> ins = ServiceLoader.load(LoaderInterface.class);
            for(LoaderInterface in : ins) {
            	in.interfaceTest();
            }
    	}
    
    }

     输出结果为

     

    展开全文
  • Android ServiceLoader使用

    2021-03-29 14:08:19
    文章目录Android ServiceLoader使用前言一、ServiceLoader什么?二、使用步骤1.准备工作最关键的一步哦了,万事俱备只欠东风,最后一步: 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的...

    Android ServiceLoader使用

    ServiceLoader使用步骤



    前言

    提示:这里可以添加本文要记录的大概内容:
    例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、ServiceLoader是什么?

    看到这里的时候笔者假设你已经知道ServiceLoader是做什么用的了。不会的请自行查阅文档

    二、使用步骤

    1.准备工作

    1. 一个android工程
    2. 新建一个module library
      里面创建一个接口,比如叫UserService
    3. app module依赖 步骤2 创建的library
      并新建一个类实现UserService接口

    最后的工程目录类似于这个样子

    在这里插入图片描述
    **

    最关键的一步

    **
    配置我们的实现类,分别在app module和library module里面创建配置文件,位置在java文件夹目录平级:META-INF/services/,创建一个文本文件,**名字命名为UserService的全路径名(就是你创建的接口类的全限定名)**内容就写你当前module内实现类的全限定名,例如我的工程配置如下:

    在这里插入图片描述

    哦了,万事俱备只欠东风,最后一步:

    如何在library内获取UserService接口所有实现类呢?

    ServiceLoader<IUserService> load = ServiceLoader.load(IUserService.class);
            
            if (load == null) {
                System.out.println("service is null");
            }else {
                for (IUserService service: load) {
                    System.out.println(service.getClass());
                    System.out.println(service.getUser());
                }
            }
    

    哦了,网上找了很多都没说META-INF 文件配置的注意事项,切记,配置文件名称是用接口的全路径名,内容是写当前模块内的实现类类名。

    欢迎同学们一起交流~~~

    展开全文
  • java SPI 01-SPI 是什么?spi 使用入门教程 ServiceLoader 使用简介.pdf
  • 浅析ServiceLoader

    2019-02-20 17:35:44
    了解ServiceLoader,需要先了解 SPI(Service Provider Interface) SPI的简单来说就是在程序设计时将一个功能服务的接口与实现分离,在程序运行时通过JVM机制自动找到服务接口的实现类并创建,以达到解耦的目的,提高...

    1.SPI的概念

    了解ServiceLoader,需要先了解 SPI(Service Provider Interface)

    SPI的简单来说就是在程序设计时将一个功能服务的接口与实现分离,在程序运行时通过JVM机制自动找到服务接口的实现类并创建,以达到解耦的目的,提高程序的可拓展性; 比如JDBC

    2.ServiceLoader

    ServiceLoader就是 Java平台提供的一个简单的 Service Provder Framework。使用ServiceLoader有简单的以下几个步骤

    • 创建服务接口
    • 在服务接口的实现模块中,创建一个实现类实现对应的服务接口,并通过在项目的resource/META-INF/services文件夹下面创建一个对应该服务接口全限定名的文本文件,在该文本文件写入该服务接口实现类的全限定名,以此达到一个注册服务的作用(项目打包后在jar文件里也得存在该文件)
    • 服务调用方(需求方)通过ServiceLoader类的load方法加载服务并得到服务的实现类

    2.1 一个简单ServiceLoader场景实例

    这里以一个简单虚拟支付场景为例。
    有一个业务模块目前需要使用支付服务,所以我们首先创建了一个PaymenService抽象接口表示 支付服务,接口类中有一个抽象方法**pay(String productName,double price)**表示支付某个商品
    ###创建服务实现模块

    package com.knight.serviceimpl;
    
    import com.knight.PaymentService;
    
    public class PaymentServiceImpl implements PaymentService {
        @Override
        public void pay(String productName, double price) {
            System.out.println("支付模块:购买产品 "+productName +",价格"+price);
        }
    }
    
    

    在IDEA中的结构如下
    image

    创建服务接口类

    image

    通过ServiceLoader获取服务

    业务模块中直接通过ServiceLoader类及PaymentService接口获取服务实例并实现业务逻辑(业务模块一般是不包含服务的实现模块的)

    package com.knight.business;
    
    import com.knight.PaymentService;
    
    import java.util.Iterator;
    import java.util.ServiceLoader;
    
    public class BusinessModule {
        public static void run(){
            Iterator<PaymentService> serviceIterator = ServiceLoader.load(PaymentService.class).iterator();
            if (serviceIterator.hasNext()){
                PaymentService paymentService = serviceIterator.next();
                paymentService.pay("Q币充值",100.00);
            }else {
                System.out.println("未找到支付模块");
            }
        }
    }
    
    

    以上的核心代码是 通过 ServiceLoader的load方法,传入PaymentService接口类,会返回一个ServiceLoader的实例对象,通过该对象的**iterator()**方法会返回一个 Iterator 的迭代器,可以通过这个迭代器得到所有PaymentService的实现对象。

    最后 我们再创建一个app模块运行业务代码逻辑,app模块包含service、service-impl、business、3个模块。

    image

    以上所有代码已上传 git

    ServiceLoader 核心源码简单解析

    ServiceLoader内部细节
    1.首先通过静态方法load获取对应服务接口的ServiceLoader实例;
    2.ServiceLoader类继承了Iterabale接口,内部实现了一个服务实例懒加载的迭代器;迭代器内部通过classLoader读 取对应META-INF/service/文件夹下的服务配置文件获取到所有的实现类类名称,当通过iterator()方法获取迭代器后,就可以依次实例化service的实现并将实现对象加入到缓存中。
    3.解析配置文件的过程就是按行读取,每一行的文本都是一个服务实现类的全限定名,获取到类名就可以通过反射实例化对象了

    public final class ServiceLoader<S>
        implements Iterable<S>
    {
        //Service配置文件的资源路径
        private static final String PREFIX = "META-INF/services/";
    
        // The class or interface representing the service being loaded
        private final Class<S> service;
    
        // 负责service配置资源加载,实例化service 
        private final ClassLoader loader;
        
            // 服务实例的缓存,已被迭代被创建过的会加到这个cache中
        private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
        
            private ServiceLoader(Class<S> svc, ClassLoader cl) {
            service = Objects.requireNonNull(svc, "Service interface cannot be null");
            loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
            reload();
        }
        //重载load, 删除缓存并重新实例化iterator
            public void reload() {
            providers.clear();
            lookupIterator = new LazyIterator(service, loader);
        }
        
        //懒加载的service迭代器
            private class LazyIterator
            implements Iterator<S>
        {
    
            Class<S> service;
            ClassLoader loader;
            Enumeration<URL> configs = null;
            Iterator<String> pending = null;
            String nextName = null;
    
            private LazyIterator(Class<S> service, ClassLoader loader) {
                this.service = service;
                this.loader = loader;
            }
    
            private boolean hasNextService() {
                if (nextName != null) {
                    return true;
                }
                //读取配置文件,最终转换成一个配置文件内容元素迭代器
                if (configs == null) {
                    try {
                        String fullName = PREFIX + service.getName();
                        if (loader == null)
                            configs = ClassLoader.getSystemResources(fullName);
                        else
                            configs = loader.getResources(fullName);
                    } catch (IOException x) {
                        fail(service, "Error locating configuration files", x);
                    }
                }
                while ((pending == null) || !pending.hasNext()) {
                    if (!configs.hasMoreElements()) {
                        return false;
                    }
                    pending = parse(service, configs.nextElement());
                }
                //获取配置文件中的下一个元素
                nextName = pending.next();
                return true;
            }
    
            private S nextService() {
                if (!hasNextService())
                    throw new NoSuchElementException();
                String cn = nextName;
                nextName = null;
                Class<?> c = null;
                try {
                    c = Class.forName(cn, false, loader);
                } catch (ClassNotFoundException x) {
                    fail(service,
                         "Provider " + cn + " not found");
                }
                if (!service.isAssignableFrom(c)) {
                    fail(service,
                         "Provider " + cn  + " not a subtype");
                }
                try {
                    S p = service.cast(c.newInstance());
                    providers.put(cn, p);
                    return p;
                } catch (Throwable x) {
                    fail(service,
                         "Provider " + cn + " could not be instantiated",
                         x);
                }
                throw new Error();          // This cannot happen
            }
    
            public boolean hasNext() {
                return hasNextService();
            }
    
            public S next() {
                return nextService();
            }
    
    
        }
        //按行读取文件,每一行都是服务实现类的接口名
        private Iterator<String> parse(Class<?> service, URL u)throws ServiceConfigurationError
            {
                InputStream in = null;
                BufferedReader r = null;
                ArrayList<String> names = new ArrayList<>();
                try {
                    in = u.openStream();
                    r = new BufferedReader(new InputStreamReader(in, "utf-8"));
                    int lc = 1;
                    while ((lc = parseLine(service, u, r, lc, names)) >= 0);
                } catch (IOException x) {
                    fail(service, "Error reading configuration file", x);
                } finally {
                    try {
                        if (r != null) r.close();
                        if (in != null) in.close();
                    } catch (IOException y) {
                        fail(service, "Error closing configuration file", y);
                    }
                }
                return names.iterator();
            }
    }
    

    Google autoService

    以上 当注册服务实现时如果需要手动创建文件并写入服务实现类名称 难免有些繁琐,我们可以使用谷歌提供的 AutoService 库简化这一过程

    使用方式

    1. gradle 引入autoService
    dependencies {
        compileOnly 'com.google.auto.service:auto-service:1.0-rc2'
        annotationProcessor 'com.google.auto.service:auto-service:1.0-rc2'
    }
    
    1. 服务实现类上加上@AutoService注解,参数为服务抽象类
    package com.knight.serviceimpl;
    
    import com.google.auto.service.AutoService;
    import com.knight.PaymentService;
    
    @AutoService(PaymentService.class)
    public class PaymentServiceImpl implements PaymentService {
        @Override
        public void pay(String productName, double price) {
            System.out.println("支付模块:购买产品 "+productName +",价格"+price);
        }
    }
    
    

    3.项目编译触发auto-service注解处理过程后自动生成了配置文件

    image

    其他

    该实例源码已上传 git仓库

    展开全文
  • java ServiceLoader

    2019-03-18 13:06:00
    看到ServiceLoader可以根据IService把定义的两个实现类找出来,返回一个ServiceLoader的实现,而ServiceLoader实现了Iterable接口,所以可以通过ServiceLoader来遍历所有在配置文件中定义的类的实例。 ...

    看到ServiceLoader可以根据IService把定义的两个实现类找出来,返回一个ServiceLoader的实现,而ServiceLoader实现了Iterable接口,所以可以通过ServiceLoader来遍历所有在配置文件中定义的类的实例。

    ServiceLoader的应用

    (1)Hadoop FileSystem

    Hadoop FileSystem就是通过这个机制来根据不同文件的scheme来返回不同的FileSystem。

    private static void loadFileSystems() {  
    
      synchronized(FileSystem.class){  
    
        if(!FILE_SYSTEMS_LOADED) {  
    
          ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class); 
    
          for(FileSystem fs : serviceLoader) {  
    
            SERVICE_FILE_SYSTEMS.put(fs.getScheme(),fs.getClass());  
    
          } 
    
          FILE_SYSTEMS_LOADED= true; 
    
        } 
    
      } 
    
    }

    通过之前的测试类输出对应的scheme和class如下: 
    file=class org.apache.hadoop.fs.LocalFileSystem   
    viewfs=class org.apache.hadoop.fs.viewfs.ViewFileSystem   
    s3=class org.apache.hadoop.fs.s3.S3FileSystem   
    s3n=class org.apache.hadoop.fs.s3native.NativeS3FileSystem   
    kfs=class org.apache.hadoop.fs.kfs.KosmosFileSystem   
    ftp=class org.apache.hadoop.fs.ftp.FTPFileSystem   
    har=class org.apache.hadoop.fs.HarFileSystem   
    hdfs=class org.apache.hadoop.hdfs.DistributedFileSystem   
    hftp=class org.apache.hadoop.hdfs.HftpFileSystem   
    hsftp=class org.apache.hadoop.hdfs.HsftpFileSystem   
    webhdfs=class org.apache.hadoop.hdfs.web.WebHdfsFileSystem  
     

    可以看到FileSystem会把所有的FileSystem的实现都以scheme和class来cache,之后就从这个cache中取相应的值。因此,以后可以通过ServiceLoader来实现一些类似的功能,而不用依赖像Spring这样的第三方框架。

    展开全文
  • ServiceLoader详解

    2018-06-25 17:16:10
    ServiceLoader与ClassLoader是Java中2个即相互区别又相互联系的加载器.JVM利用ClassLoader将类载入内存,这是一个类声明周期的第一步(一个...详情请参阅:详解Java类的生命周期那ServiceLoader又是什么呢?ServiceL...
  • ServiceLoader用法

    2021-04-14 09:45:31
    在服务的提供方可以通过ServiceLoader.load(接口名.class);来进行装载 在resources下创建META-INF下创建services,并在services下创建名字为接口的全路径名称的文件,内容写实现类的全路径名称 然后服务的使用方...
  • ServiceLoader原理

    2021-02-07 20:01:20
    ServiceLoader是jdk6里面引进的一个特性。它用来实现SPI,一种服务发现机制。SPI的全名为Service Provider Interface,主要是应用于厂商自定义组件或插件中。Java SPI机制的思想:我们系统里抽象的各个模块,往往有...
  • ServiceLoader 使用

    千次阅读 2017-05-20 23:42:58
    ServiceLoader服务提供者模式,实现动态插件加载,类责任链模式 ServiceLoader的功能比ClassLoader简单,它可以帮我们获取所有实现了某接口或基类的类。当然前提是ClassLoader已经加载过的类。举个例子: ...
  • 关于ServiceLoader

    2018-08-01 13:47:25
    1.ServiceLoader按照某种规则动态加载外部类,支持配置化方式,ClassLoader都可以加载,但有时候不如ServiceLoader方便   2.配置方式:  在META_INFO/services/接口的全路径命名的UTF-8格式的配置文件   ...
  • ServiceLoader解读

    2019-09-27 07:13:35
    在java.util.ServiceLoader的文档里有比较详细的介绍。 简单来说就是通过配置文件指定接口的实现类。 当我们开发一套框架、一套机制、一个插件或一套API时候,如果需要第三方的服务支持,可以直接写死到代码里面,...
  • 认识serviceLoader

    2015-11-05 11:05:00
    最近在研究系统设计方面的东西,发现有很多通用的解决方案,包括spring配置扩展以及serviceLoader的应用,这里简单记录下serviceLoader的简单应用,网上例子很多,大同小异,本人觉得最主要的是能懂得思想,运用到...
  • ServiceLoader的使用

    2019-09-14 17:01:09
    发现ServiceLoader是个类似spring的东西,可以指定接口和实现,通过ServiceLoader去载入。 下面是我的一个例子: Java代码 packagecom.test2; importjava.util.ServiceLoader;...
  • ServiceLoader java

    2013-02-26 17:50:12
    在JAVA版本中从6.0开始,添加了一ServiceLoader类库,在此类出现以前,Java 开发人员经常希望将使用和创建组件的内容区分开来。这通常是通过创建一个描述组件动作的接口,并使用某种中介创建组件实例来完成的。很多...
  • spi 01-spi 是什么?入门使用 spi 02-spi 的实战解决 slf4j 包冲突问题 spi 03-spi jdk 实现源码解析 spi 04-spi dubbo 实现源码解析 spi 05-dubbo adaptive extension 自适应拓展 spi 06-自己从零手写实现 SPI 框架...
  • SPI与ServiceLoader

    2020-03-29 09:07:25
    ServiceLoader与ClassLoader是Java中2个即相互区别又相互联系的加载器.JVM利用ClassLoader将类载入内存,而ServiceLoader是一个简单的服务提供者加载器,服务的对象是接口和类(通常为抽象类)集合,其也是SPI的灵魂...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,980
精华内容 2,392
关键字:

serviceloader是什么