2, SOFA RPC parsing source code - SPI articles

SOFA RPC parsing source
1, SOFA RPC source code parsing - service publishing articles
parse the source code from SOFA RPC - Services published articles in perspective there are many places I have mentioned SPI, SPI So what is it, we simply introduce the SPI under JAVA process: JAVA running process is the use of SPI java.util.ServiceLoader load method of this class to find the full file path name of the corresponding interfaces in src / META-INF / services / , then find the corresponding implementation in the file and injected achieve, then you can use. (Click JAVA SPI ), did not talk much, after we have a rough concept of spi look at SOFA RPC is how to achieve the SPI.
We started from the familiar code:

public class RpcServer {
    public static void main(String[] args) {
        // 构建RegistryConfig 注册配置
        RegistryConfig registryConfig = new RegistryConfig().setProtocol("zookeeper").setAddress("127.0.0.1:2181");
        RegistryConfig registryConfig1 = new RegistryConfig().setProtocol("zookeeper").setAddress("127.0.0.1:2181");
        List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
        registryConfigs.add(registryConfig);
        registryConfigs.add(registryConfig1);
        // 构建ServerConfig 服务配置
        List<ServerConfig> serverConfigs = new ArrayList<ServerConfig>();
        ServerConfig serverConfig = new ServerConfig().setProtocol("bolt").setPort(12200).setDaemon(false);
        ServerConfig serverConfig1 = new ServerConfig().setProtocol("rest").setPort(12200).setDaemon(false);
        serverConfigs.add(serverConfig);
        serverConfigs.add(serverConfig1);
        // 构建发布配置
        ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>().setApplication(new ApplicationConfig().setAppName("paul")).setInterfaceId(HelloService.class.getName()).setRef(new HelloServiceImpl()).setServer(serverConfigs).setRegistry(registryConfig);
        // 正式发布
        providerConfig.export();
    }
}

Above that code is my first post SOFA RPC source code parsing - service publishing articles inside,
we'll simply break down again, to build RegistryConfig registered from first step in configuring which used the SPI terms:
point into the parent AbstractIdConfig RegistryConfig

/**
 * 默认配置带ID
 *
 * @param <S> the sub class of AbstractIdConfig
 * @author <a href=mailto:[email protected]>GengZhang</a>
 */
public abstract class AbstractIdConfig<S extends AbstractIdConfig> implements Serializable {

    private static final long          serialVersionUID = -1932911135229369183L;

    /**
     * Id生成器
     */
    private final static AtomicInteger ID_GENERATOR     = new AtomicInteger(0);

    static {
        RpcRuntimeContext.now();
    }
    ...

Then point into static modules in the RpcRuntimeContext, found:

    static {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Welcome! Loading SOFA RPC Framework : {}, PID is:{}", Version.BUILD_VERSION, PID);
        }
        put(RpcConstants.CONFIG_KEY_RPC_VERSION, Version.RPC_VERSION);
        // 初始化一些上下文
        initContext();
        // 初始化其它模块
        ModuleFactory.installModules();
        // 增加jvm关闭事件
        if (RpcConfigs.getOrDefaultValue(RpcOptions.JVM_SHUTDOWN_HOOK, true)) {
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    if (LOGGER.isWarnEnabled()) {
                        LOGGER.warn("SOFA RPC Framework catch JVM shutdown event, Run shutdown hook now.");
                    }
                    destroy(false);
                }
            }, "SOFA-RPC-ShutdownHook"));
        }
    }

This inside ModuleFactory.installModules (); it uses SPI, a configuration of the expansion module is loaded, with a look:

    /**
     * 加载全部模块
     */
    public static void installModules() {
        ExtensionLoader<Module> loader = ExtensionLoaderFactory.getExtensionLoader(Module.class);
        String moduleLoadList = RpcConfigs.getStringValue(RpcOptions.MODULE_LOAD_LIST);
        for (Map.Entry<String, ExtensionClass<Module>> o : loader.getAllExtensions().entrySet()) {
            String moduleName = o.getKey();
            Module module = o.getValue().getExtInstance();
            // judge need load from rpc option
            if (needLoad(moduleLoadList, moduleName)) {
                // judge need load from implement
                if (module.needLoad()) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Install Module: {}", moduleName);
                    }
                    module.install();
                    INSTALLED_MODULES.put(moduleName, module);
                } else {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("The module " + moduleName + " does not need to be loaded.");
                    }
                }
            } else {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("The module " + moduleName + " is not in the module load list.");
                }
            }
        }
    }

The above code, ExtensionLoader loader = ExtensionLoaderFactory.getExtensionLoader (Module.class); which is the core of SPI

   /**
     * Get extension loader by extensible class with listener
     *
     * @param clazz    Extensible class
     * @param listener Listener of ExtensionLoader
     * @param <T>      Class
     * @return ExtensionLoader of this class
     */
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> clazz, ExtensionLoaderListener<T> listener) {
        // 第一次进来loader 肯定是空的
        ExtensionLoader<T> loader = LOADER_MAP.get(clazz);
        if (loader == null) {
            // 锁住class,双重校验,防止重复初始化
            synchronized (ExtensionLoaderFactory.class) {
                loader = LOADER_MAP.get(clazz);
                if (loader == null) {
                    // 实例化 loader
                    loader = new ExtensionLoader<T>(clazz, listener);
                    LOADER_MAP.put(clazz, loader);
                }
            }
        }
        return loader;
    }

    /**
     * Get extension loader by extensible class without listener
     *
     * @param clazz Extensible class
     * @param <T>   Class
     * @return ExtensionLoader of this class
     */
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> clazz) {
        return getExtensionLoader(clazz, null);
    }

I wrote a simple above comments, the most important word is loader = new ExtensionLoader (Clazz, listener); point we go in and see it done in the end it!

    /**
     * 构造函数(自动加载)
     *
     * @param interfaceClass 接口类
     * @param listener       加载后的监听器
     */
    public ExtensionLoader(Class<T> interfaceClass, ExtensionLoaderListener<T> listener) {
        this(interfaceClass, true, listener);
    }
    
    /**
     * 构造函数(主要测试用)
     *
     * @param interfaceClass 接口类
     * @param autoLoad       是否自动开始加载
     * @param listener       扩展加载监听器
     */
    protected ExtensionLoader(Class<T> interfaceClass, boolean autoLoad, ExtensionLoaderListener<T> listener) {
        // 如果RPC框架正在关闭则属性全部初始化为空return
        if (RpcRunningState.isShuttingDown()) {
            this.interfaceClass = null;
            this.interfaceName = null;
            this.listener = null;
            this.factory = null;
            this.extensible = null;
            this.all = null;
            return;
        }
        // 接口为空,既不是接口,也不是抽象类,要求必须是接口或者抽象类,会自动加载所有实现类
        if (interfaceClass == null ||
            !(interfaceClass.isInterface() || Modifier.isAbstract(interfaceClass.getModifiers()))) {
            throw new IllegalArgumentException("Extensible class must be interface or abstract class!");
        }
        this.interfaceClass = interfaceClass;
        this.interfaceName = ClassTypeUtils.getTypeStr(interfaceClass);
        this.listener = listener;
        // 获取extensible注解,上面会有几个属性file指定扩展文件名称,singleton是否单例,coded是否需要编码
        Extensible extensible = interfaceClass.getAnnotation(Extensible.class);
        if (extensible == null) {
            throw new IllegalArgumentException(
                "Error when load extensible interface " + interfaceName + ", must add annotation @Extensible.");
        } else {
            this.extensible = extensible;
        }
        // 如果是单例的,则存入factory,也就是一个线程安全的ConcurrentHashMap
        this.factory = extensible.singleton() ? new ConcurrentHashMap<String, T>() : null;
        // 初始化一个保存全部扩展的对象的ConcurrentMap
        this.all = new ConcurrentHashMap<String, ExtensionClass<T>>();
        // 是否自动加载,一般都是是
        if (autoLoad) {
            // 从配置中心或者配置文件中加载扩展类文件相对路径
            List<String> paths = RpcConfigs.getListValue(RpcOptions.EXTENSION_LOAD_PATH);
            for (String path : paths) {
                // 这个就是最重要的一步,解析文件!
                loadFromFile(path);
            }
        }
    }
    /**
     * @param path path必须以/结尾
     */
    protected synchronized void loadFromFile(String path) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Loading extension of extensible {} from path: {}", interfaceName, path);
        }
        // 默认如果不指定文件名字,就是接口名
        String file = StringUtils.isBlank(extensible.file()) ? interfaceName : extensible.file().trim();
        // 获得完整的相对地址
        String fullFileName = path + file;
        try {
            // 获得当前类的类加载器,这个是用来获取resource的也就是获取资源文件
            ClassLoader classLoader = ClassLoaderUtils.getClassLoader(getClass());
            loadFromClassLoader(classLoader, fullFileName);
        } catch (Throwable t) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("Failed to load extension of extensible " + interfaceName + " from path:" + fullFileName,
                    t);
            }
        }
    }
    protected void loadFromClassLoader(ClassLoader classLoader, String fullFileName) throws Throwable {
        // 根据全路径名从classLoader里面获取资源文件
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources(fullFileName)
            : ClassLoader.getSystemResources(fullFileName);
        // 可能存在多个文件。
        if (urls != null) {
            while (urls.hasMoreElements()) {
                // 读取一个文件
                URL url = urls.nextElement();
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Loading extension of extensible {} from classloader: {} and file: {}",
                        interfaceName, classLoader, url);
                }
                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        // 读取处理逻辑
                        readLine(url, line);
                    }
                } catch (Throwable t) {
                    if (LOGGER.isWarnEnabled()) {
                        LOGGER.warn("Failed to load extension of extensible " + interfaceName
                            + " from classloader: " + classLoader + " and file:" + url, t);
                    }
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                }
            }
        }
    }
    protected void readLine(URL url, String line) {
        // 解析一行,获取他们的别名和className,这个方法里对空做了处理,别名为空时仍可正常返回
        String[] aliasAndClassName = parseAliasAndClassName(line);
        if (aliasAndClassName == null || aliasAndClassName.length != 2) {
            return;
        }
        String alias = aliasAndClassName[0];
        String className = aliasAndClassName[1];
        // 读取配置的实现类
        Class tmp;
        try {
            tmp = ClassUtils.forName(className, false);
        } catch (Throwable e) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Extension {} of extensible {} is disabled, cause by: {}",
                    className, interfaceName, ExceptionUtils.toShortString(e, 2));
            }
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Extension " + className + " of extensible " + interfaceName + " is disabled.", e);
            }
            return;
        }
        // 用来判断A类是否是B类的子类或者子接口,Object是所有类的父类 
        // [isAssignableFrom](https://www.cnblogs.com/paul-lb/p/11344584.html)
        if (!interfaceClass.isAssignableFrom(tmp)) {
            throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                " from file:" + url + ", " + className + " is not subtype of interface.");
        }
        Class<? extends T> implClass = (Class<? extends T>) tmp;

        // 检查是否有可扩展标识,就是子类上面的Extension 注解
        Extension extension = implClass.getAnnotation(Extension.class);
        if (extension == null) {
            throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                " from file:" + url + ", " + className + " must add annotation @Extension.");
        } else {
            // 获取注解上面的扩展点名字必须写,不写就会报错
            String aliasInCode = extension.value();
            if (StringUtils.isBlank(aliasInCode)) {
                // 扩展实现类未配置@Extension 标签
                throw new IllegalArgumentException("Error when load extension of extensible " + interfaceClass +
                    " from file:" + url + ", " + className + "'s alias of @Extension is blank");
            }
            // 从配置文件取的别名,前面说了如果别名为空仍可正常返回
            if (alias == null) {
                // spi文件里没配置,用代码里的
                alias = aliasInCode;
            } else {
                // spi文件里配置的和代码里的不一致
                if (!aliasInCode.equals(alias)) {
                    throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                        " from file:" + url + ", aliases of " + className + " are " +
                        "not equal between " + aliasInCode + "(code) and " + alias + "(file).");
                }
            }
            // 接口需要编号,实现类没设置
            if (extensible.coded() && extension.code() < 0) {
                throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                    " from file:" + url + ", code of @Extension must >=0 at " + className + ".");
            }
        }
        // 不可以是default和*
        if (StringUtils.DEFAULT.equals(alias) || StringUtils.ALL.equals(alias)) {
            throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                " from file:" + url + ", alias of @Extension must not \"default\" and \"*\" at " + className + ".");
        }
        // 检查是否有存在同名的
        ExtensionClass old = all.get(alias);
        ExtensionClass<T> extensionClass = null;
        if (old != null) {
            // 如果当前扩展可以覆盖其它同名扩展
            if (extension.override()) {
                // 如果优先级还没有旧的高,则忽略
                if (extension.order() < old.getOrder()) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Extension of extensible {} with alias {} override from {} to {} failure, " +
                            "cause by: order of old extension is higher",
                            interfaceName, alias, old.getClazz(), implClass);
                    }
                } else {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Extension of extensible {} with alias {}: {} has been override to {}",
                            interfaceName, alias, old.getClazz(), implClass);
                    }
                    // 如果当前扩展可以覆盖其它同名扩展
                    extensionClass = buildClass(extension, implClass, alias);
                }
            }
            // 如果旧扩展是可覆盖的
            else {
                if (old.isOverride() && old.getOrder() >= extension.order()) {
                    // 如果已加载覆盖扩展,再加载到原始扩展
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Extension of extensible {} with alias {}: {} has been loaded, ignore origin {}",
                            interfaceName, alias, old.getClazz(), implClass);
                    }
                } else {
                    // 如果不能被覆盖,抛出已存在异常
                    throw new IllegalStateException(
                        "Error when load extension of extensible " + interfaceClass + " from file:" + url +
                            ", Duplicate class with same alias: " + alias + ", " + old.getClazz() + " and " + implClass);
                }
            }
        } else {
            extensionClass = buildClass(extension, implClass, alias);
        }
        if (extensionClass != null) {
            // 检查是否有互斥的扩展点
            for (Map.Entry<String, ExtensionClass<T>> entry : all.entrySet()) {
                ExtensionClass existed = entry.getValue();
                if (extensionClass.getOrder() >= existed.getOrder()) {
                    // 新的优先级 >= 老的优先级,检查新的扩展是否排除老的扩展
                    String[] rejection = extensionClass.getRejection();
                    if (CommonUtils.isNotEmpty(rejection)) {
                        for (String rej : rejection) {
                            existed = all.get(rej);
                            if (existed == null || extensionClass.getOrder() < existed.getOrder()) {
                                continue;
                            }
                            ExtensionClass removed = all.remove(rej);
                            if (removed != null) {
                                if (LOGGER.isInfoEnabled()) {
                                    LOGGER.info(
                                        "Extension of extensible {} with alias {}: {} has been reject by new {}",
                                        interfaceName, removed.getAlias(), removed.getClazz(), implClass);
                                }
                            }
                        }
                    }
                } else {
                    String[] rejection = existed.getRejection();
                    if (CommonUtils.isNotEmpty(rejection)) {
                        for (String rej : rejection) {
                            if (rej.equals(extensionClass.getAlias())) {
                                // 被其它扩展排掉
                                if (LOGGER.isInfoEnabled()) {
                                    LOGGER.info(
                                        "Extension of extensible {} with alias {}: {} has been reject by old {}",
                                        interfaceName, alias, implClass, existed.getClazz());
                                    return;
                                }
                            }
                        }
                    }
                }
            }

            loadSuccess(alias, extensionClass);
        }
    }
    // 将实现类class别名等属性初始化到ExtensionClass里
    private ExtensionClass<T> buildClass(Extension extension, Class<? extends T> implClass, String alias) {
        ExtensionClass<T> extensionClass = new ExtensionClass<T>(implClass, alias);
        extensionClass.setCode(extension.code());
        extensionClass.setSingleton(extensible.singleton());
        extensionClass.setOrder(extension.order());
        extensionClass.setOverride(extension.override());
        extensionClass.setRejection(extension.rejection());
        return extensionClass;
    }
    // 如果有监听器则通知监听器,加入全部的加载的实现类 {"alias":ExtensionClass} all
    private void loadSuccess(String alias, ExtensionClass<T> extensionClass) {
        if (listener != null) {
            try {
                listener.onLoad(extensionClass); // 加载完毕,通知监听器
                all.put(alias, extensionClass);
            } catch (Exception e) {
                LOGGER.error("Error when load extension of extensible " + interfaceClass + " with alias: "
                    + alias + ".", e);
            }
        } else {
            all.put(alias, extensionClass);
        }
    }

Here we talked about the loading process on spi finished, we now look at his last operation, how to take a loaded object class initialization get it?

    /**
     * 加载全部模块
     */
    public static void installModules() {
        ExtensionLoader<Module> loader = ExtensionLoaderFactory.getExtensionLoader(Module.class);
        String moduleLoadList = RpcConfigs.getStringValue(RpcOptions.MODULE_LOAD_LIST);
        for (Map.Entry<String, ExtensionClass<Module>> o : loader.getAllExtensions().entrySet()) {
            String moduleName = o.getKey();
            // 从这里可以看出来调用的是getExtInstance()
            Module module = o.getValue().getExtInstance();
            // judge need load from rpc option
            if (needLoad(moduleLoadList, moduleName)) {
                // judge need load from implement
                if (module.needLoad()) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Install Module: {}", moduleName);
                    }
                    module.install();
                    INSTALLED_MODULES.put(moduleName, module);
                } else {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("The module " + moduleName + " does not need to be loaded.");
                    }
                }
            } else {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("The module " + moduleName + " is not in the module load list.");
                }
            }
        }
    }

    /**
     * 得到服务端实例对象,如果是单例则返回单例对象,如果不是则返回新创建的实例对象
     *
     * @return 扩展点对象实例
     */
    public T getExtInstance() {
        return getExtInstance(null, null);
    }
    
    /**
     * 得到服务端实例对象,如果是单例则返回单例对象,如果不是则返回新创建的实例对象
     *
     * @param argTypes 构造函数参数类型
     * @param args     构造函数参数值
     * @return 扩展点对象实例 ext instance
     */
    public T getExtInstance(Class[] argTypes, Object[] args) {
        if (clazz != null) {
            try {
                // 这个singleton是在加载spi的时候从extensible上面取出注入的哦
                if (singleton) { // 如果是单例
                    if (instance == null) {
                        synchronized (this) {
                            if (instance == null) {
                                // 这里面是自动检测构造方法是否跟传的参数一直,一直则使用该构造器构造对象
                                instance = ClassUtils.newInstanceWithArgs(clazz, argTypes, args);
                            }
                        }
                    }
                    return instance; // 保留单例
                } else {
                    // 这里面是自动检测构造方法是否跟传的参数一直,一直则使用该构造器构造对象
                    return ClassUtils.newInstanceWithArgs(clazz, argTypes, args);
                }
            } catch (Exception e) {
                throw new SofaRpcRuntimeException("create " + clazz.getCanonicalName() + " instance error", e);
            }
        }
        throw new SofaRpcRuntimeException("Class of ExtensionClass is null");
    }

According to the discussion above spi extend out initialization class object parameters are based on an automatic call to the constructor to construct the pass out, but the distinction between singleton and extended by non-singleton embodiment uses a single double-check lock + the way to ensure that only initialized once!
Well, today all of our analysis SOFA RPC SPI to end here, reading is not that pretty easy, here I come full summary process:
1, according to the class name to get passed in the extended class class Interface , Extensible notes
2, loading according to the Extensible information is complete file to configure the relative path corresponding extended file, and obtains a length of array 2
3. className array configured to load the appropriate class object, and determines whether the object incoming class is a subclass of
4, according to the configuration of the same name to check on the cover extension, and the like check mutex extension point
5, the initialization data to the ExtensionClass
. 6, and the obtained alias ExtensionClass stored to prepare for the next ConcurrentMap -use
summary of the end, is not very simple!

Guess you like

Origin www.cnblogs.com/paul-lb/p/11358229.html