All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.microsphere.util.ServiceLoaderUtils Maven / Gradle / Ivy

The newest version!
package io.microsphere.util;

import io.microsphere.lang.Prioritized;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

import static io.microsphere.collection.CollectionUtils.toIterable;
import static io.microsphere.collection.ListUtils.newLinkedList;
import static io.microsphere.collection.MapUtils.newConcurrentHashMap;
import static io.microsphere.text.FormatUtils.format;
import static io.microsphere.util.ArrayUtils.asArray;
import static io.microsphere.util.ClassLoaderUtils.getClassLoader;
import static io.microsphere.util.ClassLoaderUtils.getDefaultClassLoader;
import static java.lang.Boolean.getBoolean;
import static java.util.Collections.sort;
import static java.util.Collections.unmodifiableList;

/**
 * {@link ServiceLoader} Utility
 *
 * @author Mercy
 * @version 1.0.0
 * @see ServiceLoader
 * @since 1.0.0
 */
public abstract class ServiceLoaderUtils extends BaseUtils {

    private static final Map, ServiceLoader>> serviceLoadersCache = new ConcurrentHashMap<>();

    private static final boolean serviceLoaderCached = getBoolean("microsphere.service-loader.cached");

    /**
     * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher)
     * will be able to load the configuration file META-INF/services serviceType under its class path.
     * The configuration file of each service type can define multiple lists of implementation classes.
     * 

* * @param service type * @param serviceType service type * @return service type all implementation objects of {@link Collections#unmodifiableList(List) readonly list} * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static List loadServicesList(Class serviceType) throws IllegalArgumentException { return loadServicesList(serviceType, getClassLoader(serviceType)); } /** * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher) * will be able to load the configuration file META-INF/services serviceType under its class path. * The configuration file of each service type can define multiple lists of implementation classes. *

* * @param service type * @param serviceType service type * @param classLoader {@link ClassLoader} * @return service type all implementation objects of {@link Collections#unmodifiableList(List) readonly list} * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static List loadServicesList(Class serviceType, ClassLoader classLoader) throws IllegalArgumentException { return loadServicesList(serviceType, classLoader, serviceLoaderCached); } /** * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher) * will be able to load the configuration file META-INF/services serviceType under its class path. * The configuration file of each service type can define multiple lists of implementation classes. *

* * @param service type * @param serviceType service type * @param cached the list of services to be cached * @return service type all implementation objects of {@link Collections#unmodifiableList(List) readonly list} * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static List loadServicesList(Class serviceType, boolean cached) throws IllegalArgumentException { return loadServicesList(serviceType, getClassLoader(serviceType), cached); } /** * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher) * will be able to load the configuration file META-INF/services serviceType under its class path. * The configuration file of each service type can define multiple lists of implementation classes. *

* * @param service type * @param serviceType service type * @param classLoader {@link ClassLoader} * @param cached the list of services to be cached * @return service type all implementation objects of {@link Collections#unmodifiableList(List) readonly list} * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static List loadServicesList(Class serviceType, ClassLoader classLoader, boolean cached) throws IllegalArgumentException { return unmodifiableList(loadServicesList0(serviceType, classLoader, cached)); } /** * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher) * will be able to load the configuration file META-INF/services serviceType under its class path. * The configuration file of each service type can define multiple lists of implementation classes. *

* * @param service type * @param serviceType service type * @return service type all implementation objects * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static S[] loadServices(Class serviceType) throws IllegalArgumentException { return loadServices(serviceType, getClassLoader(serviceType)); } /** * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher) * will be able to load the configuration file META-INF/services serviceType under its class path. * The configuration file of each service type can define multiple lists of implementation classes. *

* * @param service type * @param serviceType service type * @param classLoader {@link ClassLoader} * @return service type all implementation objects * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static S[] loadServices(Class serviceType, ClassLoader classLoader) throws IllegalArgumentException { return loadServices(serviceType, classLoader, serviceLoaderCached); } /** * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher) * will be able to load the configuration file META-INF/services serviceType under its class path. * The configuration file of each service type can define multiple lists of implementation classes. *

* * @param service type * @param serviceType service type * @param cached the list of services to be cached * @return service type all implementation objects * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static S[] loadServices(Class serviceType, boolean cached) throws IllegalArgumentException { return loadServices(serviceType, getClassLoader(serviceType), cached); } /** * Using the hierarchy of {@link ClassLoader}, each level of ClassLoader ( ClassLoader , its parent ClassLoader and higher) * will be able to load the configuration file META-INF/services serviceType under its class path. * The configuration file of each service type can define multiple lists of implementation classes. *

* * @param service type * @param serviceType service type * @param classLoader {@link ClassLoader} * @param cached the list of services to be cached * @return service type all implementation objects * @throws IllegalArgumentException If it refers to the implementation class that does not define serviceType * in the configuration file /META-INF/services/serviceType */ public static S[] loadServices(Class serviceType, ClassLoader classLoader, boolean cached) throws IllegalArgumentException { return asArray(loadServicesList0(serviceType, classLoader, cached), serviceType); } /** * Load the first instance of {@link #loadServicesList(Class) Service interface instances list} *

* Design Purpose : Using the hierarchy of {@link ClassLoader}, each level of ClassLoader will be able to access the configuration files under its class path * /META-INF/services/serviceType. * Then, override the first implementation class of the configuration file under the class path of ClassLoader, * thereby providing a mechanism for overriding the implementation class. * * @param service type * @param serviceType service type * @return If it exists, {@link #loadServicesList(Class, ClassLoader) loads the first in the list of implementation objects of service type}. * @throws IllegalArgumentException If the implementation class that does not define serviceType is in the configuration file * META-INF/services/serviceType, IllegalArgumentException will be thrown */ public static S loadFirstService(Class serviceType) throws IllegalArgumentException { return loadFirstService(serviceType, getClassLoader(serviceType)); } /** * Load the first instance of {@link #loadServicesList(Class) Service interface instances list} *

* Design Purpose : Using the hierarchy of {@link ClassLoader}, each level of ClassLoader will be able to access the configuration files under its class path * /META-INF/services/serviceType. * Then, override the first implementation class of the configuration file under the class path of ClassLoader, * thereby providing a mechanism for overriding the implementation class. * * @param service type * @param serviceType service type * @param cached the list of services to be cached * @return If it exists, {@link #loadServicesList(Class, ClassLoader) loads the first in the list of implementation objects of service type}. * @throws IllegalArgumentException If the implementation class that does not define serviceType is in the configuration file * META-INF/services/serviceType, IllegalArgumentException will be thrown */ public static S loadFirstService(Class serviceType, boolean cached) throws IllegalArgumentException { return loadFirstService(serviceType, getClassLoader(serviceType), cached); } /** * Load the first instance of {@link #loadServicesList(Class, ClassLoader) Service interface instances list} *

* Design Purpose : Using the hierarchy of {@link ClassLoader}, each level of ClassLoader will be able to access the configuration files under its class path * /META-INF/services/serviceType. * Then, override the first implementation class of the configuration file under the class path of ClassLoader, * thereby providing a mechanism for overriding the implementation class. * * @param service type * @param serviceType service type * @return If it exists, {@link #loadServicesList(Class, ClassLoader) loads the first in the list of implementation objects of service type}. * @throws IllegalArgumentException If the implementation class that does not define serviceType is in the configuration file * META-INF/services/serviceType, IllegalArgumentException will be thrown */ public static S loadFirstService(Class serviceType, ClassLoader classLoader) throws IllegalArgumentException { return loadFirstService(serviceType, classLoader, serviceLoaderCached); } /** * Load the first instance of {@link #loadServicesList(Class, ClassLoader) Service interface instances list} *

* Design Purpose : Using the hierarchy of {@link ClassLoader}, each level of ClassLoader will be able to access the configuration files under its class path * /META-INF/services/serviceType. * Then, override the first implementation class of the configuration file under the class path of ClassLoader, * thereby providing a mechanism for overriding the implementation class. * * @param service type * @param serviceType service type * @param cached the list of services to be cached * @return If it exists, {@link #loadServicesList(Class, ClassLoader) loads the first in the list of implementation objects of service type}. * @throws IllegalArgumentException If the implementation class that does not define serviceType is in the configuration file * META-INF/services/serviceType, IllegalArgumentException will be thrown */ public static S loadFirstService(Class serviceType, ClassLoader classLoader, boolean cached) throws IllegalArgumentException { return loadService(serviceType, classLoader, cached, true); } /** * Loads the last in the list of objects implementing the service type, if present. *

*

* Design Purpose : Using the hierarchy of {@link ClassLoader}, once the configuration file is loaded in the parent's ClassLoader at a higher level (here the highest-level ClassLoader is Bootstrap ClassLoader) * /META-INF/services/serviceType * If the last implementation class is used, the lower-level Class Loader will not be able to override the previous definition。 * * @param service type * @param serviceType service type * @return Loads the last in the list of objects implementing the service type, if present. * @throws IllegalArgumentException see {@link #loadServicesList(Class, ClassLoader)} */ public static S loadLastService(Class serviceType) throws IllegalArgumentException { return loadLastService(serviceType, getClassLoader(serviceType)); } /** * Loads the last in the list of objects implementing the service type, if present. *

*

* Design Purpose : Using the hierarchy of {@link ClassLoader}, once the configuration file is loaded in the parent's ClassLoader at a higher level (here the highest-level ClassLoader is Bootstrap ClassLoader) * /META-INF/services/serviceType * If the last implementation class is used, the lower-level Class Loader will not be able to override the previous definition。 * * @param service type * @param serviceType service type * @param cached the list of services to be cached * @return Loads the last in the list of objects implementing the service type, if present. * @throws IllegalArgumentException see {@link #loadServicesList(Class, ClassLoader)} */ public static S loadLastService(Class serviceType, boolean cached) throws IllegalArgumentException { return loadLastService(serviceType, getClassLoader(serviceType), cached); } /** * Loads the last in the list of objects implementing the service type, if present. *

*

* Design Purpose : Using the hierarchy of {@link ClassLoader}, once the configuration file is loaded in the parent's ClassLoader at a higher level (here the highest-level ClassLoader is Bootstrap ClassLoader) * /META-INF/services/serviceType * If the last implementation class is used, the lower-level Class Loader will not be able to override the previous definition。 * * @param service type * @param serviceType service type * @param classLoader {@link ClassLoader} * @return Loads the last in the list of objects implementing the service type, if present. * @throws IllegalArgumentException see {@link #loadServicesList(Class, ClassLoader)} */ public static S loadLastService(Class serviceType, ClassLoader classLoader) throws IllegalArgumentException { return loadLastService(serviceType, classLoader, serviceLoaderCached); } /** * Loads the last in the list of objects implementing the service type, if present. *

*

* Design Purpose : Using the hierarchy of {@link ClassLoader}, once the configuration file is loaded in the parent's ClassLoader at a higher level (here the highest-level ClassLoader is Bootstrap ClassLoader) * /META-INF/services/serviceType * If the last implementation class is used, the lower-level Class Loader will not be able to override the previous definition。 * * @param service type * @param serviceType service type * @return Loads the last in the list of objects implementing the service type, if present. * @throws IllegalArgumentException see {@link #loadServicesList(Class, ClassLoader)} */ public static S loadLastService(Class serviceType, ClassLoader classLoader, boolean cached) throws IllegalArgumentException { return loadService(serviceType, classLoader, cached, false); } public static ServiceLoader load(Class serviceType, ClassLoader classLoader, boolean cached) { if (cached) { Map, ServiceLoader> serviceLoadersMap = serviceLoadersCache.computeIfAbsent(classLoader, cl -> newConcurrentHashMap()); return (ServiceLoader) serviceLoadersMap.computeIfAbsent(serviceType, type -> ServiceLoader.load(serviceType, classLoader)); } return ServiceLoader.load(serviceType, classLoader); } private static S loadService(Class serviceType, ClassLoader classLoader, boolean cached, boolean first) { List serviceList = loadServicesList0(serviceType, classLoader, cached); int index = first ? 0 : serviceList.size() - 1; return serviceList.get(index); } /** * Load all instances of service type * * @param service type * @param serviceType service type * @param classLoader {@link ClassLoader} * @param cached the list of services to be cached * @return Load all instances of service type * @throws IllegalArgumentException see {@link #loadServicesList(Class, ClassLoader)} */ private static List loadServicesList0(Class serviceType, ClassLoader classLoader, boolean cached) throws IllegalArgumentException { if (classLoader == null) { classLoader = getDefaultClassLoader(); } ServiceLoader serviceLoader = load(serviceType, classLoader, cached); Iterator iterator = serviceLoader.iterator(); List serviceList = newLinkedList(toIterable(iterator)); if (serviceList.isEmpty()) { String className = serviceType.getName(); String message = format("No Service interface[type : %s] implementation was defined in service loader configuration file[/META-INF/services/%s] under ClassLoader[%s]", className, className, classLoader); throw new IllegalArgumentException(message); } sort(serviceList, Prioritized.COMPARATOR); return serviceList; } }