Spi扩展加载机制_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Spi扩展加载机制

Spi扩展加载机制

 2017/11/1 0:11:38  qq466862016  程序员俱乐部  我要评论(0)
  • 摘要:一、概述我们都知道Java的SPI机制:(serviceproviderinterface)对于该机制的详情概述请自行百度。packagecom.shotdog.panda.core.extension;importcom.shotdog.panda.core.common.annotation.Spi;importcom.shotdog.panda.core.common.annotation.SpiMeta;importcom.shotdog.panda.core.common.enums
  • 标签:

?

?一、概述

? ? ? ?我们都知道 Java的SPI机制:(service provider interface ) 对于该机制的详情概述请自行百度。

class="java" name="code">package com.shotdog.panda.core.extension;

import com.shotdog.panda.core.common.annotation.Spi;
import com.shotdog.panda.core.common.annotation.SpiMeta;
import com.shotdog.panda.core.common.enums.Scope;
import com.shotdog.panda.core.exception.PandaFrameworkException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/***
 * Spi 扩展加载器
 * jdk  spi 增强
 * 
 * @date 2017-10-31 21:42:04
 */
public class ExtensionLoader<T> {

    private final static Logger log = LoggerFactory.getLogger(ExtensionLoader.class);

    private final static String PREFIX = "META-INF/services/";

    private Class<T> type;

    private ClassLoader classLoader;

    private volatile transient boolean init;

    private ConcurrentHashMap<String, Class<T>> extensions = new ConcurrentHashMap<String, Class<T>>();
    private ConcurrentHashMap<String, T> singletons;


    private static ConcurrentHashMap<Class<?>, ExtensionLoader<?>> extensionLoaders = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();


    public ExtensionLoader(Class<T> type) {
        this(type, Thread.currentThread().getContextClassLoader());
    }

    public ExtensionLoader(Class<T> type, ClassLoader classLoader) {
        this.type = type;
        this.classLoader = classLoader;
    }


    /**
     * 获取扩展加载器
     *
     * @param clz
     * @param <T>
     * @return
     */
    public synchronized static <T> ExtensionLoader<T> getExtensionLoader(Class<T> clz) {

        checkInterface(clz);
        ExtensionLoader<?> extensionLoader = extensionLoaders.get(clz);
        if (extensionLoader != null) return (ExtensionLoader<T>) extensionLoader;

        return newExtensionLoader(clz);

    }


    /**
     * 创建一个新的扩展加载器
     *
     * @param clz
     * @param <T>
     * @return
     */
    private static <T> ExtensionLoader<T> newExtensionLoader(Class<T> clz) {

        ExtensionLoader<?> extensionLoader = extensionLoaders.get(clz);
        if (extensionLoader != null) return (ExtensionLoader<T>) extensionLoader;

        ExtensionLoader<T> loader = new ExtensionLoader<T>(clz);
        extensionLoaders.putIfAbsent(clz, loader);
        return loader;

    }

    /**
     * 检查接口是否为扩展加载的接口
     *
     * @param clz
     * @param <T>
     */
    private static <T> void checkInterface(Class<T> clz) {

        if (clz == null) {

            throw new PandaFrameworkException("extension loader service interface is not allow null");
        }

        if (!clz.isAnnotationPresent(Spi.class)) {

            throw new PandaFrameworkException(String.format("extension loader service interface has no (%s) annotation", Spi.class.getName()));
        }

    }


    /***
     * 获取扩展加载服务对象
     * @param name
     * @return
     */
    public T getExtension(String name) {

        if (!init) {
            this.initExtensionLoader();
        }

        Class<T> clz = this.extensions.get(name);
        if (clz == null) return null;

        try {


            Spi spi = type.getAnnotation(Spi.class);
            if (spi.scope() == Scope.SINGLETON) {

                return this.newInstanceToSingleton(clz, name);

            } else {

                return clz.newInstance();

            }
        } catch (Exception e) {
            throw new PandaFrameworkException(String.format("class:(%) newInstance fail", clz.getName()));

        }


    }

    /**
     * 创建一个新的单例对象
     *
     * @param clz
     * @param name
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private T newInstanceToSingleton(Class<T> clz, String name) throws IllegalAccessException, InstantiationException {

        synchronized (singletons) {

            T t = this.singletons.get(name);
            if (t != null) return t;

            t = clz.newInstance();

            this.singletons.putIfAbsent(name, t);
            return t;
        }
    }

    private void initExtensionLoader() {


        this.extensions = this.loadExtensions();
        this.singletons = new ConcurrentHashMap<String, T>();
        this.init = true;


    }

    private ConcurrentHashMap<String, Class<T>> loadExtensions() {

        String configFiles = PREFIX + this.type.getName();

        List<String> classNames = new ArrayList<String>();

        try {

            Enumeration<URL> url = null;
            if (this.classLoader == null) {
                url = ClassLoader.getSystemResources(configFiles);
            } else {
                url = this.classLoader.getResources(configFiles);
            }


            while (url.hasMoreElements()) {

                URL u = url.nextElement();

                this.parseUrl(u, classNames);

            }


        } catch (Exception e) {

            throw new PandaFrameworkException(String.format("extension loader loadExtensions :(%s) fail", configFiles), e);
        }


        return this.loadAllClasses(classNames);
    }

    /***
     * 加载所有的类
     * @param classNames
     * @return
     */
    private ConcurrentHashMap<String, Class<T>> loadAllClasses(List<String> classNames) {
        ConcurrentHashMap<String, Class<T>> classes = new ConcurrentHashMap<String, Class<T>>();
        if (classNames == null || classNames.isEmpty()) return classes;

        for (String className : classNames) {


            try {

                Class<T> clz = null;

                if (this.classLoader == null) {
                    clz = (Class<T>) Class.forName(className);
                } else {
                    clz = (Class<T>) Class.forName(className, false, this.classLoader);
                }

                this.checkExtensionType(clz);

                String name = this.getSpiName(clz);

                if (!classes.containsKey(name)) {

                    classes.putIfAbsent(name, clz);
                }
            } catch (Exception e) {

                throw new PandaFrameworkException(String.format("extension loader load class:(%s)  fail", className));
            }

        }


        return null;
    }

    /**
     * 获取spi服务名称
     *
     * @param clz
     * @return
     */
    private String getSpiName(Class<T> clz) {

        SpiMeta spiMeta = clz.getAnnotation(SpiMeta.class);
        if (spiMeta != null && StringUtils.isNotBlank(spiMeta.name())) {
            return spiMeta.name();
        }

        return clz.getSimpleName();
    }

    /***
     *  检查扩展服务类类型
     * @param clz
     */
    private void checkExtensionType(Class<T> clz) {


        // 检查是否为 public 类型
        if (!Modifier.isPublic(clz.getModifiers())) {
            throw new PandaFrameworkException(String.format("class :(%s) is not public type class", clz.getName()));
        }

        // 检查是否为spi服务接口实现类

        if (!clz.isAssignableFrom(type)) {
            throw new PandaFrameworkException(String.format("class :(%s) is not assignable from interface ", clz.getName(), type.getName()));
        }
        // 检查是否有无参数默认构造方法

        Constructor<?>[] constructors = clz.getConstructors();

        for (Constructor constructor : constructors) {

            if (constructor.getParameterTypes().length == 0) {
                return;
            }
        }


        throw new PandaFrameworkException(String.format("class :(%s) is has not default constructor method ", clz.getName()));


    }

    /**
     * 解析每个 url
     *
     * @param url
     * @param classNames
     */
    private void parseUrl(URL url, List<String> classNames) throws IOException {

        InputStream inputStream = null;
        BufferedReader reader = null;
        try {

            inputStream = url.openStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));

            while (this.parseReadLine(reader, classNames) > 0) ;

        } catch (Exception e) {

            throw new PandaFrameworkException("extension loader parseUrl fail");
        } finally {


            try {

                if (reader != null) reader.close();
                if (inputStream != null) inputStream.close();

            } catch (Exception e) {
                // ignore
            }
        }

    }

    /**
     * 读取每一行
     *
     * @param reader
     * @param classNames
     * @return
     * @throws IOException
     */
    private int parseReadLine(BufferedReader reader, List<String> classNames) throws IOException {

        String line = reader.readLine();
        if (line == null) return -1;

        int index = line.indexOf("#");
        if (index >= 0) line = line.substring(0, index);

        line = line.trim();

        int length = line.length();
        if (length > 0) {

            if (line.indexOf(' ') >= 0 || line.indexOf('\t') > 0) {

                throw new PandaFrameworkException(String.format("Syntax error:(%s)", line));
            }

            // 校验首字母
            int codePoint = line.codePointAt(0);
            if (!Character.isJavaIdentifierStart(codePoint)) {

                throw new PandaFrameworkException(String.format("Syntax error:(%s)", line));
            }

            // 循环检查内容是否合法

            for (int i = Character.charCount(codePoint); i < length; i += Character.charCount(codePoint)) {

                codePoint = line.codePointAt(i);
                if (!Character.isJavaIdentifierPart(codePoint) && codePoint != '.') {

                    throw new PandaFrameworkException(String.format("Syntax error:(%s)", line));
                }

                if (!classNames.contains(line)) {
                    classNames.add(line);
                }


            }


        }


        return length + 1;
    }


}

?

?

  • 相关文章
发表评论
用户名: 匿名