Java SPI机制:ServiceLoader实现原理及应用剖析

您所在的位置:网站首页 spi机制实现原理 Java SPI机制:ServiceLoader实现原理及应用剖析

Java SPI机制:ServiceLoader实现原理及应用剖析

2023-09-16 19:37| 来源: 网络整理| 查看: 265

一、背景

SPI,全称Service Provider Interfaces,服务提供接口。是Java提供的一套供第三方实现或扩展使用的技术体系。主要通过解耦服务具体实现以及服务使用,使得程序的可扩展性大大增强,甚至可插拔。

基于服务的注册与发现机制,服务提供者向系统注册服务,服务使用者通过查找发现服务,可以达到服务的提供与使用的分离,甚至完成对服务的管理。

JDK中,基于SPI的思想,提供了默认具体的实现,ServiceLoader。利用JDK自带的ServiceLoader,可以轻松实现面向服务的注册与发现,完成服务提供与使用的解耦。

完成分离后的服务,使得服务提供方的修改或替换,不会给服务使用方带来代码上的修改,基于面向接口的服务约定,提供方和使用方各自直接面向接口编程,而不用关注对方的具体实现。同时,服务使用方使用到服务时,也才会真正意义上去发现服务,以完成服务的初始化,形成了服务的动态加载。

在Java或Android系统实现或项目实践领域,也有直接基于ServiceLoader的功能实现,或基于ServiceLoader实现基础上,对其进行的进一步扩展与优化使用。

二、ServiceLoader实现原理

先看一下JDK中ServiceLoader的具体实现。 ServiceLoader位于java.util包中,其主体部分,代码如下:

public final class ServiceLoader implements Iterable { private static final String PREFIX = "META-INF/services/"; // The class or interface representing the service being loaded private final Class service; // The class loader used to locate, load, and instantiate providers private final ClassLoader loader; // The access control context taken when the ServiceLoader is created private final AccessControlContext acc; // Cached providers, in instantiation order private LinkedHashMap providers = new LinkedHashMap(); // The current lazy-lookup iterator private LazyIterator lookupIterator; public void reload() { providers.clear(); lookupIterator = new LazyIterator(service, loader); } private ServiceLoader(Class svc, ClassLoader cl) { service = Objects.requireNonNull(svc, "Service interface cannot be null"); loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; reload(); } // Private inner class implementing fully-lazy provider lookup private class LazyIterator implements Iterator { Class service; ClassLoader loader; Enumeration configs = null; Iterator pending = null; String nextName = null; private LazyIterator(Class 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() { if (acc == null) { return hasNextService(); } else { PrivilegedAction action = new PrivilegedAction() { public Boolean run() { return hasNextService(); } }; return AccessController.doPrivileged(action, acc); } } public S next() { if (acc == null) { return nextService(); } else { PrivilegedAction action = new PrivilegedAction() { public S run() { return nextService(); } }; return AccessController.doPrivileged(action, acc); } } public void remove() { throw new UnsupportedOperationException(); } } public Iterator iterator() { return new Iterator() { Iterator knownProviders = providers.entrySet().iterator(); public boolean hasNext() { if (knownProviders.hasNext()) return true; return lookupIterator.hasNext(); } public S next() { if (knownProviders.hasNext()) return knownProviders.next().getValue(); return lookupIterator.next(); } public void remove() { throw new UnsupportedOperationException(); } }; } public Iterator iterator() { return new Iterator() { Iterator knownProviders = providers.entrySet().iterator(); public boolean hasNext() { if (knownProviders.hasNext()) return true; return lookupIterator.hasNext(); } public S next() { if (knownProviders.hasNext()) return knownProviders.next().getValue(); return lookupIterator.next(); } public void remove() { throw new UnsupportedOperationException(); } }; } public static ServiceLoader load(Class service, ClassLoader loader) { return new ServiceLoader(service, loader); } public static ServiceLoader load(Class service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); } public static ServiceLoader loadInstalled(Class service) { ClassLoader cl = ClassLoader.getSystemClassLoader(); ClassLoader prev = null; while (cl != null) { prev = cl; cl = cl.getParent(); } return ServiceLoader.load(service, prev); } public String toString() { return "java.util.ServiceLoader[" + service.getName() + "]"; }

外部使用时,往往通过load(Class service, ClassLoader loader)或load(Class service)调用,最后都是在reload方法中创建了LazyIterator对象,LazyIterator是ServiceLoader的内部类,实现了Iterator接口,其作用是一个懒加载的迭代器,在hasNextService方法中,完成了对位于META-INF/services/目录下的配置文件的解析,并在nextService方法中,完成了对具体实现类的实例化。

META-INF/services/,是ServiceLoader中约定的接口与实现类的关系配置目录,文件名是接口全限定类名,内容是接口对应的具体实现类,如果有多个实现类,分别将不同的实现类都分别作为每一行去配置。解析过程中,通过LinkedHashMap数据结构的providers,将已经发现了的接口实现类进行了缓存,并对外提供的iterator()方法,方便外部遍历。

Android中使用的是OpenJDK,其ServiceLoader的实现与Java JDK中稍有不同,但主体逻辑和实现过程都是一致的。

总体上,ServiceLoader的一般实现与使用过程包含了服务接口约定、服务实现、服务注册、服务发现与使用这四个步骤。

如下是一个简单的Java项目中,ServiceLoader使用示例。

项目结构: -------------- |____src | |____main | | |____resources | | | |____META-INF | | | | |____services | | | | | |____com.corn.javalib.IMyServiceProvider | | |____java | | | |____com | | | | |____corn | | | | | |____javalib | | | | | | |____IMyServiceProvider.java | | | | | | |____TestClass.java | | | | | | |____MyServiceProviderImpl2.java | | | | | | |____MyServiceProviderImpl1.java

1,服务接口约定: IMyServiceProvider定义了服务的接口约定:

package com.corn.javalib; public interface IMyServiceProvider { String getName(); }

2,服务实现: MyServiceProviderImpl1、MyServiceProviderImpl2是具体的接口实现类:

package com.corn.javalib; public class MyServiceProviderImpl1 implements IMyServiceProvider { @Override public String getName() { return "name:ProviderImpl1"; } } package com.corn.javalib; public class MyServiceProviderImpl2 implements IMyServiceProvider { @Override public String getName() { return "name:ProviderImpl2"; } }

3,服务注册(实际上向系统登记服务提供者与服务接口之间的映射关系,以便使用方的服务发现): /META-INF/services/目录下创建文件com.corn.javalib.IMyServiceProvider,内容为:

com.corn.javalib.MyServiceProviderImpl1 com.corn.javalib.MyServiceProviderImpl2

4,服务发现与使用: TestClass.java为服务使用方。

package com.corn.javalib; import java.util.Iterator; import java.util.ServiceLoader; public class TestClass { public static void main(String[] argus){ ServiceLoader serviceLoader = ServiceLoader.load(IMyServiceProvider.class); Iterator iterator = serviceLoader.iterator(); while (iterator.hasNext()){ IMyServiceProvider item = (IMyServiceProvider)iterator.next(); System.out.println(item.getName() + ": " + item.hashCode()); } } }

输出结果为:

name:ProviderImpl1: 491044090 name:ProviderImpl2: 644117698 三、ServiceLoader使用实例 3.1 注解处理器的发现过程

使用到编译时注解时,定义注解并在目标元素上标注上注解后,都还需要定义一个具体的注解处理器。注解处理器的作用在于对注解的发现与处理,如实现自定义的注解处理逻辑,生成新的Java文件等。那注解处理器是如何在编译阶段被Javac编译器发现并调用的呢,这其中的过程实际上用到了ServiceLoader机制。

Javac编译过程中,会执行注解处理器发现和调用流程,Javac本身也是用java编写的,同时去编译java源码文件的编译工具。为了方便阐述Javac中与注解处理器相关的逻辑,可以在自定义的注解处理器中故意抛出异常。以查看大概的执行路径。

Caused by: java.lang.NullPointerException at com.corn.apt.AnnotationProcessor.process(AnnotationProcessor.java:42) at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794) at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705) at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91) at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035) at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176) at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170) at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856) at com.sun.tools.javac.main.Main.compile(Main.java:523)

如上,是大概的执行流程。Open JDK中自带了Javac的源码,可以下载下来,主要的Javac源码部分位于包:com.sun.tools.javac下。对照上述抛出的错误信息路径,梳理下具体的执行流程。 1,javac从com.sun.tools.javac.main.Main.compile开始执行,其中调用了JavaCompiler的compile方法,compile方法具体定义如下:

public void compile(List sourceFileObject) throws Throwable { compile(sourceFileObject, List.nil(), null); }

其内部调用的compile方法,主体部分逻辑如下:

public void compile(List sourceFileObjects, List classnames, Iterable) result; } catch (Throwable t) { log.error("proc.service.problem"); throw new Abort(t); } } public boolean hasNext() { try { return iterator.hasNext(); } catch (Throwable t) { if ("ServiceConfigurationError". equals(t.getClass().getSimpleName())) { log.error("proc.bad.config.file", t.getLocalizedMessage()); } throw new Abort(t); } } public Processor next() { try { return (Processor)(iterator.next()); } catch (Throwable t) { if ("ServiceConfigurationError". equals(t.getClass().getSimpleName())) { log.error("proc.bad.config.file", t.getLocalizedMessage()); } else { log.error("proc.processor.constructor.error", t.getLocalizedMessage()); } throw new Abort(t); } } public void remove() { throw new UnsupportedOperationException(); } }

终于,我们发现,ServiceIterator提供了适合于平台的服务发现机制,发现注解处理器。其中,优先通过反射的方式,去动态调用了java.util.ServiceLoader对应的load方法,具体是通过语句Object result = loadMethod.invoke(null, Processor.class, classLoader)实现,其中,传入了接口参数Processor.class以此完成了基于ServiceLoader的服务动态发现过程。

查找到注解处理器后,后续主要就是通过调用对应注解处理器中的方法,如自定义的注解处理器中常常重写的init和process方法等,以此实现注解处理器所需要完成的针对注解这块的逻辑处理。

至此,编译时的注解处理器的服务发现,实际上是通过ServiceLoader去实现的,流程上已经相对清晰。

对应的,我们也知道,在定义完具体的注解处理器后,需要我们在对应的/META-INF/services/中去注册Processor接口与具体的注解处理器实现类之间的关系。当然,这一步操作也可以听过Google AutoService去完成。

3.2 基于ServiceLoader实现不同组件间的通信与解耦

Android项目组件化过程中,不具有依赖关系的组件或模块间,常常涉及到组件间服务的提供与使用,如A模块需要调用B模块的方法等。基于ServiceLoader机制,实际上已经为我们提供了一种Android组件化之间的组件解耦与通信机制。通过将接口约定下沉到公共baseLib模块,不同的模块内可以按照实际需要,提供接口的具体实现,其他模块直接通过形如ServiceLoader.load(IMyServiceProvider.class)方式,即可得到具体的服务并调用之。

下面是一个简单的Android组件化后的项目工程结构示例:

.libBase |____build.gradle |____src | |____main | | |____res | | | |____drawable | | | |____values | | | | |____strings.xml | | |____AndroidManifest.xml | | |____java | | | |____com | | | | |____corn | | | | | |____libbase | | | | | | |____IMyServiceProvider.java .LibA |____libs |____build.gradle |____src | |____main | | |____res | | | |____drawable | | | |____values | | | | |____strings.xml | | |____resources | | | |____META-INF | | | | |____services | | | | | |____com.corn.libbase.IMyServiceProvider | | |____AndroidManifest.xml | | |____java | | | |____com | | | | |____corn | | | | | |____liba | | | | | | |____MyServiceProviderImpl2.java | | | | | | |____MyServiceProviderImpl1.java .LibB |____build.gradle |____src | |____main | | |____res | | | |____drawable | | | |____values | | | | |____strings.xml | | |____resources | | | |____META-INF | | | | |____services | | | | | |____com.corn.libbase.IMyServiceProvider | | |____AndroidManifest.xml | | |____java | | | |____com | | | | |____corn | | | | | |____libb | | | | | | |____MyServiceProviderImpl3.java

通过将服务接口约定定义在libBase模块,具体的服务实现提供可以在LibA或LibB等上层模块,然后分别在META-INF/services/中注册对应的接口与服务实现之间的关系,使得打包后合并对应的映射关系。

项目中其他模块,也可以直接通过形如如下方式去调用具体的服务方法。

ServiceLoader serviceLoader = ServiceLoader.load(IMyServiceProvider.class); Iterator iterator = serviceLoader.iterator(); while (iterator.hasNext()){ IMyServiceProvider item = (IMyServiceProvider)iterator.next(); Log.d(TAG, item.getName() + ": " + item.hashCode()); }

如果是在release环境下,还需要针对接口和实现类配置反混淆。否则一旦混淆后,基于接口名或接口实现的配置文件中将不能找到对应的目标类。

以此,通过基于系统ServiceLoader的方式,通过面向接口的编程方式,实现了组件间的服务解耦。

3.3 美团WMRouter中对ServiceLoader的改进与使用

我们发现,ServiceLoder每次load过程,实际上都重走了整个的ServiceLoder过程,因此,如果直接采用ServiceLoder,每次都需要对具体实现类都重走了查找和通过反射去实例化等过程,且针对同一接口,可能有多个不同的服务实现。

在借鉴系统ServiceLoader思想和实现过程的基础上,美团WMRouter中,对ServiceLoader进行了改进,主要改进点如下: 1,将系统ServiceLoader中的服务注册从系统原来的/META-INF/services/中定义改成了WMRouter中封装好的ServiceLoader中的静态Map SERVICES属性和ServiceLoader实例的HashMap mMap中。 SERVICES是一个静态变量,存储的是接口与对应的ServiceLoader关系映射, mMap作为ServiceLoader的内部属性,存储的是对应ServiceLoader实例中每个接口实现类的key(每个key表示每个不同的接口实现)和对应的实现类的关系映射。 2,可以通过上述的每个接口的key,让使用方去具体调用接口的某个具体实现服务。 3,接口实现类,通过反射创建的对象,可以决定是否存置于SingletonPool单例池中,以方便接口实现类的下次使用,相当于做了一次对象的缓存。

下面具体看下WMRouter中关于ServiceLoader改造部分的源码实现。

ServiceLoader实现:

package com.sankuai.waimai.router.service; import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.sankuai.waimai.router.annotation.RouterProvider; import com.sankuai.waimai.router.components.RouterComponents; import com.sankuai.waimai.router.core.Debugger; import com.sankuai.waimai.router.interfaces.Const; import com.sankuai.waimai.router.utils.LazyInitHelper; import com.sankuai.waimai.router.utils.SingletonPool; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 通过接口Class获取实现类 * * @param 接口类型 */ public class ServiceLoader { private static final Map SERVICES = new HashMap(); private static final LazyInitHelper sInitHelper = new LazyInitHelper("ServiceLoader") { @Override protected void doInit() { try { // 反射调用Init类,避免引用的类过多,导致main dex capacity exceeded问题 Class.forName(Const.SERVICE_LOADER_INIT) .getMethod(Const.INIT_METHOD) .invoke(null); Debugger.i("[ServiceLoader] init class invoked"); } catch (Exception e) { Debugger.fatal(e); } } }; /** * @see LazyInitHelper#lazyInit() */ public static void lazyInit() { sInitHelper.lazyInit(); } /** * 提供给InitClass使用的初始化接口 * * @param interfaceClass 接口类 * @param implementClass 实现类 */ public static void put(Class interfaceClass, String key, Class implementClass, boolean singleton) { ServiceLoader loader = SERVICES.get(interfaceClass); if (loader == null) { loader = new ServiceLoader(interfaceClass); SERVICES.put(interfaceClass, loader); } loader.putImpl(key, implementClass, singleton); } /** * 根据接口获取 {@link ServiceLoader} */ @SuppressWarnings("unchecked") public static ServiceLoader load(Class interfaceClass) { sInitHelper.ensureInit(); if (interfaceClass == null) { Debugger.fatal(new NullPointerException("ServiceLoader.load的class参数不应为空")); return EmptyServiceLoader.INSTANCE; } ServiceLoader service = SERVICES.get(interfaceClass); if (service == null) { synchronized (SERVICES) { service = SERVICES.get(interfaceClass); if (service == null) { service = new ServiceLoader(interfaceClass); SERVICES.put(interfaceClass, service); } } } return service; } /** * key --> class name */ private HashMap mMap = new HashMap(); private final String mInterfaceName; private ServiceLoader(Class interfaceClass) { if (interfaceClass == null) { mInterfaceName = ""; } else { mInterfaceName = interfaceClass.getName(); } } private void putImpl(String key, Class implementClass, boolean singleton) { if (key != null && implementClass != null) { mMap.put(key, new ServiceImpl(key, implementClass, singleton)); } } /** * 创建指定key的实现类实例,使用 {@link RouterProvider} 方法或无参数构造。对于声明了singleton的实现类,不会重复创建实例。 * * @return 可能返回null */ public T get(String key) { return createInstance(mMap.get(key), null); } /** * 创建指定key的实现类实例,使用Context参数构造。对于声明了singleton的实现类,不会重复创建实例。 * * @return 可能返回null */ public T get(String key, Context context) { return createInstance(mMap.get(key), new ContextFactory(context)); } /** * 创建指定key的实现类实例,使用指定的Factory构造。对于声明了singleton的实现类,不会重复创建实例。 * * @return 可能返回null */ public T get(String key, IFactory factory) { return createInstance(mMap.get(key), factory); } /** * 创建所有实现类的实例,使用 {@link RouterProvider} 方法或无参数构造。对于声明了singleton的实现类,不会重复创建实例。 * * @return 可能返回EmptyList,List中的元素不为空 */ @NonNull public List getAll() { return getAll((IFactory) null); } /** * 创建所有实现类的实例,使用Context参数构造。对于声明了singleton的实现类,不会重复创建实例。 * * @return 可能返回EmptyList,List中的元素不为空 */ @NonNull public List getAll(Context context) { return getAll(new ContextFactory(context)); } /** * 创建所有实现类的实例,使用指定Factory构造。对于声明了singleton的实现类,不会重复创建实例。 * * @return 可能返回EmptyList,List中的元素不为空 */ @NonNull public List getAll(IFactory factory) { Collection services = mMap.values(); if (services.isEmpty()) { return Collections.emptyList(); } List list = new ArrayList(services.size()); for (ServiceImpl impl : services) { T instance = createInstance(impl, factory); if (instance != null) { list.add(instance); } } return list; } /** * 获取指定key的实现类。注意,对于声明了singleton的实现类,获取Class后还是可以创建新的实例。 * * @return 可能返回null */ @SuppressWarnings("unchecked") public Class getClass(String key) { return (Class) mMap.get(key).getImplementationClazz(); } /** * 获取所有实现类的Class。注意,对于声明了singleton的实现类,获取Class后还是可以创建新的实例。 * * @return 可能返回EmptyList,List中的元素不为空 */ @SuppressWarnings("unchecked") @NonNull public List getAllClasses() { List list = new ArrayList(mMap.size()); for (ServiceImpl impl : mMap.values()) { Class clazz = (Class) impl.getImplementationClazz(); if (clazz != null) { list.add(clazz); } } return list; } @SuppressWarnings("unchecked") @Nullable private T createInstance(@Nullable ServiceImpl impl, @Nullable IFactory factory) { if (impl == null) { return null; } Class clazz = (Class) impl.getImplementationClazz(); if (impl.isSingleton()) { try { return SingletonPool.get(clazz, factory); } catch (Exception e) { Debugger.fatal(e); } } else { try { if (factory == null) { factory = RouterComponents.getDefaultFactory(); } T t = factory.create(clazz); Debugger.i("[ServiceLoader] create instance: %s, result = %s", clazz, t); return t; } catch (Exception e) { Debugger.fatal(e); } } return null; } @Override public String toString() { return "ServiceLoader (" + mInterfaceName + ")"; } public static class EmptyServiceLoader extends ServiceLoader { public static final ServiceLoader INSTANCE = new EmptyServiceLoader(); public EmptyServiceLoader() { super(null); } @NonNull @Override public List getAllClasses() { return Collections.emptyList(); } @NonNull @Override public List getAll() { return Collections.emptyList(); } @NonNull @Override public List getAll(IFactory factory) { return Collections.emptyList(); } @Override public String toString() { return "EmptyServiceLoader"; } } }

首先通过对外提供了doInit方法,让系统通过反射的方式调用ServiceLoaderInit类的init方法,通过调用ServiceLoader.put方法,将接口、接口实现类的key和接口实现类,依次装载进SERVICES和mMap中。以此完成了映射关系的注册。通过Router类,进一步封装好对ServiceLoader的调用,以方便外部适用方更方便的去使用,最终通过如Router.getService(ILocationService.class, "keyValue")等方式去调用。

WMRouterServiceLoader本身,其他的服务查找,服务具体实现类的初始化等相对都比较简单,下面重点看下服务实现类的实例缓存逻辑。

@Nullable private T createInstance(@Nullable ServiceImpl impl, @Nullable IFactory factory) { if (impl == null) { return null; } Class clazz = (Class) impl.getImplementationClazz(); if (impl.isSingleton()) { try { return SingletonPool.get(clazz, factory); } catch (Exception e) { Debugger.fatal(e); } } else { try { if (factory == null) { factory = RouterComponents.getDefaultFactory(); } T t = factory.create(clazz); Debugger.i("[ServiceLoader] create instance: %s, result = %s", clazz, t); return t; } catch (Exception e) { Debugger.fatal(e); } } return null; }

createInstance方法中,通过判断impl.isSingleton(),来决定是否从SingletonPool中读取缓存的对象实例。SingletonPool是一个单例缓存类,其中通过静态的CACHE常量,缓存了对应的类class与已经实例化过的对象之间的映射关系,下次再次需要读取时,直接判断CACHE中是否已经存在单例对象,有则直接取出,否则创建并存入。

/** * 单例缓存 * */ public class SingletonPool { private static final Map CACHE = new HashMap(); @SuppressWarnings("unchecked") public static T get(Class clazz, IFactory factory) throws Exception { if (clazz == null) { return null; } if (factory == null) { factory = RouterComponents.getDefaultFactory(); } Object instance = getInstance(clazz, factory); Debugger.i("[SingletonPool] get instance of class = %s, result = %s", clazz, instance); return (T) instance; } @NonNull private static Object getInstance(@NonNull Class clazz, @NonNull IFactory factory) throws Exception { Object t = CACHE.get(clazz); if (t != null) { return t; } else { synchronized (CACHE) { t = CACHE.get(clazz); if (t == null) { Debugger.i("[SingletonPool] >>> create instance: %s", clazz); t = factory.create(clazz); //noinspection ConstantConditions if (t != null) { CACHE.put(clazz, t); } } } return t; } } }

SingletonPool的存在,避免了ServiceLoader可能需要的重复实例化过程,但同时,带来的问题是服务对象的生命周期的延长化,会导致长期占据内存。由此,作为框架提供方,特意在服务具体实现类的注解上,加上了一个singleton参数供使用方去决定此服务实现类是否采用单例形式,以决定是否需要缓存。

也就是常见的具体服务类的实现上,注解写法形式如下:

@RouterService(interfaces = IAccountService.class, key = DemoConstant.SINGLETON, singleton = true) public class FakeAccountService implements IAccountService { ... }

至此,WMRouter中对ServiceLoader的改进部分分析完成。

四、结语

基于服务提供与发现的思想,系统自带的ServiceLoader以及基于此思想基础上的演化形式,被广泛的使用到实际的项目中。本质上,通过服务接口约定、服务注册与服务发现,完成将服务提供方与服务使用方的解耦,大大扩展了系统的可扩展性。服务注册的本质,是将服务接口与具体服务实现的映射关系注册到系统或特定实现中。服务发现的过程,本质上是向系统或特定实现去匹配对应的具体实现类,但在写法上是基于接口的编程方式,因为服务使用方和服务提供方彼此都是透明与未感知的。基于SPI思想的ServiceLoader实现及演化,在项目的组件化,或实现扩展性功能,甚至完成具有可插拔能力的插件化模块时,往往都被广泛使用到。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3