sofa源码学习----启动获取ServerConfig流程

蚂蚁金服sofa rpc框架。公司想使用它作为架构的一部分,所以记录学习笔记。

1.从github下载源代码,版本为 5.6.0-SNAPSHOT,整个项目结构如下:


 

2.为了尽可能地只关注sofa 本身,所以没有下载 和springboot整合的项目,只是sofa本身。

3.本节学习sofa server端加载启动配置文件过程,即 获取 ServerConfig 过程。


4.在源码中example模块下quickstart中找到 QuickStartServer 这个类,debug启动;

5.

6.关键代码在 QuickStartServer类的第28行:

ServerConfig serverConfig = new ServerConfig();

/**
 * 服务端配置
 *
 */
public class ServerConfig extends AbstractIdConfig implements Serializable {
}

从上面红色箭头可以看到 大概调用流程是:

ServerConfig serverConfig = new ServerConfig() -> AbstractIdConfig()
AbstractIdConfig类中:
static {
    RpcRuntimeContext.now();
}

进入到  RpcRuntimeContext 类中初始化

进而进入到 LoggerFactory 类的初始化

进而进入到 RpcConfigs 类的初始化

/**
 * 配置加载器和操作入口
 */
public class RpcConfigs {

    /**
     * 全部配置
     */
    private final static ConcurrentMap<String, Object>                  CFG          = new ConcurrentHashMap<String, Object>();
    /**
     * 配置变化监听器
     */
    private final static ConcurrentMap<String, List<RpcConfigListener>> CFG_LISTENER = new ConcurrentHashMap<String, List<RpcConfigListener>>();

    static {
        init(); // 加载配置文件
    }

    // ... ...
}

关键是上面 init()方法,加载配置文件;

private static void init() {
        try {
            // loadDefault
            String json = FileUtils.file2String(RpcConfigs.class, "rpc-config-default.json", "UTF-8");
            Map map = JSON.parseObject(json, Map.class);
            CFG.putAll(map);

            // loadCustom
            loadCustom("sofa-rpc/rpc-config.json");
            loadCustom("META-INF/sofa-rpc/rpc-config.json");

            // load system properties
            CFG.putAll(new HashMap(System.getProperties())); // 注意部分属性可能被覆盖为字符串
        } catch (Exception e) {
            throw new SofaRpcRuntimeException("Catch Exception when load RpcConfigs", e);
        }
    }

我们先看 loadDefault下面那一行代码:

            String json = FileUtils.file2String(RpcConfigs.class, "rpc-config-default.json", "UTF-8");

FileUtils所在位置如下【common模块下com.alipay.sofa.rpc.common.utils.FileUtils】:

rpc-config-default.json 内容如下:

/*
本文件为SOFA RPC客户端内置的默认配置文件。
用户可以在自己的工程中自定义rpc-config.json进行默认配置覆盖。
所有的属性均可配置。(通过-D或者setProperty)

PS:大家也看到了,本JSON文档是支持注释的,而标准JSON是不支持的,这属于宽松的的json格式
*/
{
  /*-------------RPC框架内部使用配置项-------------*/
  // 本配置文件加载顺序,越大越后加载
  "rpc.config.order": 0,
  // 日志实现,日志早于配置加载,所以不能适应Extension机制
  "logger.impl": "com.alipay.sofa.rpc.log.SLF4JLoggerImpl",
  // 扩展点加载的路径
  "extension.load.path": [
    "META-INF/services/sofa-rpc/",
    "META-INF/services/"
  ],
  // 需要被加载的模块列表,多个用逗号隔开
  "module.load.list" : "*",
  /*-------------RPC框架内部使用配置项-------------*/


  /*-------------系统运行时相关配置开始-------------*/
  // 0代表自动判断,也可以自定义注入,或者启动参数注入
  "system.cpu.cores": 0,
  // 是否允许线程上下文携带自定义参数,默认true,关闭后,可能tracer等会失效,但是会提高性能
  "context.attachment.enable": true,
  // 是否启动事件总线,关闭后,可能tracer等会失效,但是可以提高性能
  "event.bus.enable": true,
  // 主动监听JVM关闭事件,默认true,如果有外部管理框架,可以由外部开启回收
  "jvm.shutdown.hook": true,
  // 是否增加序列化安全黑名单,关闭后可提供性能
  "serialize.blacklist.enable": false,
  // 是否支持多ClassLoader支持,如果是单ClassLoader环境,可以关闭提高性能
  "multiple.classloader.enable": false,
  // 是否允许请求和响应透传数据,关闭后,会提高性能
  "invoke.baggage.enable": false,
  /*-------------系统运行时相关配置开始-------------*/


  /*-------------默认配置值开始-------------*/
  // 默认Provider启动器
  "default.provider.bootstrap": "sofa",
  // 默认Consumer启动器
  "default.consumer.bootstrap": "sofa",
  // 默认uniqueId 做为服务唯一标识
  "default.uniqueId": "",
  // 默认version 不做为服务唯一标识
  "default.version": "",
  // 默认分组 不做为服务唯一标识
  "default.group": "",
  // 默认注册中心
  "default.registry": "zookeeper",
  // 默认协议
  "default.protocol": "bolt",
  // 默认序列化
  "default.serialization": "hessian2",
  // 默认压缩算法
  "default.compress": "snappy",
  // 默认代理类
  "default.proxy": "javassist",
  // 默认字符集
  "default.charset": "UTF-8",
  // 默认网络层
  "default.transport": "netty4",
  // 默认tracer实现
  "default.tracer": "",
  /*-------------默认配置值结束-------------*/


  /*-------------Registry相关配置开始-------------*/
  // 注册中心地址发现服务 的地址
  "registry.index.address": "",
  /* 默认连注册中心的超时时间*/
  "registry.connect.timeout": 20000,
  // 注册中心等待结果的超时时间
  "registry.disconnect.timeout": 10000,
  // 注册中心调用超时时间
  "registry.invoke.timeout": 10000,
  // 注册中心心跳发送间隔
  "registry.heartbeat.period": 30000,
  // 注册中心重建连接的间隔
  "registry.reconnect.period": 30000,
  // 是否开启有注册中心的批量注册/反注册  boolean  默认true,重连或者销毁时采用批量的方式。配为false则采取旧方式。  1.6.0
  "registry.batch": false,
  // 如果开启,批量的条数
  "registry.batch.size": 10,
  /*-------------Registry相关配置开始-------------*/

  /*-------------Server相关配置开始-------------*/
  // 默认绑定网卡
  "server.host": "0.0.0.0",
  // 端口段开始
  "server.port.start": 12200,
  // 端口段结束
  "server.port.end": 65535,
  // 默认contextPath
  "server.context.path": "",
  // 默认io线程大小,推荐自动设置
  "server.ioThreads": 0,
  // 默认业务线程池类型
  "server.pool.type": "cached",
  // 默认业务线程池最小
  "server.pool.core": 20,
  // 默认业务线程池最大
  "server.pool.max": 200,
  // 是否允许telnet,针对自定义协议
  "server.telnet": true,
  // 默认普通业务线程池队列
  "server.pool.queue.type": "normal",
  // 默认业务线程池队列大小
  "server.pool.queue": 0,
  //  默认业务线程池回收时间
  "server.pool.aliveTime": 60000,
  // 默认业务线程池是否初始化核心线程
  "server.pool.pre.start": false,
  // 最大支持长连接
  "server.accepts": 100000,
  // 是否启动epoll
  "server.epoll": false,
  // 是否hold住端口,true的话随主线程退出而退出,false的话则要主动退出
  "server.daemon": false,
  // 端口是否自适应,如果端口被占用,自动+1
  "server.adaptive.port": false,
  // 服务端是否自动启动
  "server.auto.start": true,
  // 服务端关闭超时时间
  "server.stop.timeout": 20000,
  /*-------------Server相关配置结束-------------*/


  /*-------------Provider&Consumer公共配置开始-------------*/
  //默认服务是否注册
  "service.register": true,
  //默认服务是否订阅
  "service.subscribe": true,
  /*-------------Provider&Consumer公共配置公共配置结束-------------*/


  /*-------------Provider相关配置开始-------------*/
  //默认服务端权重
  "provider.weight": 100,
  // 默认发布延迟,代表spring启动后触发
  "provider.delay": -1,
  // 默认发布方法:全部
  "provider.include": "*",
  // 默认不发布方法
  "provider.exclude": "",
  // 默认动态注册,false代表不主动发布
  "provider.dynamic": true,
  // 接口优先级
  "provider.priority": 0,
  //服务端调用超时, 不打断执行。0表示不判断
  "provider.invoke.timeout": 0,
  //接口下每方法的最大可并行执行请求数,配置-1关闭并发过滤器,等于0表示开启过滤但是不限制
  "provider.concurrents": 0,
  // 同一个服务(接口协议uniqueId相同)的最大发布次数,防止由于代码bug导致重复发布。注意:后面的发布可能会覆盖前面的实现
  "provider.repeated.export.limit": 1,
  /*-------------Provider相关配置结束-------------*/


  /*-------------Consumer相关配置开始-------------*/
  // 集群策略
  "consumer.cluster": "failover",
  // 默认连接全部建立长连接
  "consumer.connectionHolder": "all",
  // 默认单分组
  "consumer.addressHolder": "singleGroup",
  // 负载均衡
  "consumer.loadBalancer": "random",
  //默认失败重试次数
  "consumer.retries": 0,
  //接口下每方法的最大可并行执行请求数,配置-1关闭并发过滤器,等于0表示开启过滤但是不限制
  "consumer.concurrents": 0,
  // 默认是否异步
  "consumer.invokeType": "sync",
  // 默认不延迟加载
  "consumer.lazy": false,
  // 默认粘滞连接
  "consumer.sticky": false,
  // 是否jvm内部调用(provider和consumer配置在同一个jvm内,则走本地jvm内部,不走远程)
  "consumer.inJVM": false,
  // 是否强依赖(即没有服务节点就启动失败)
  "consumer.check": false,
  // 默认长连接数
  "consumer.connection.num": 1,
  // 默认consumer连provider超时时间
  "consumer.connect.timeout": 5000,
  // 默认consumer断开时等待结果的超时时间
  "consumer.disconnect.timeout": 10000,
  // 默认consumer调用provider超时时间
  "consumer.invoke.timeout": 3000,
  // 心跳发送间隔
  "consumer.heartbeat.period": 30000,
  // 重建连接间隔
  "consumer.reconnect.period": 10000,
  // 等待地址时间,-1表示一直等
  "consumer.address.wait": -1,
  // 同一个服务(接口协议uniqueId相同)的最大引用次数,防止由于代码bug导致重复引用,每次引用都会生成一个代理类对象
  "consumer.repeated.reference.limit": 3,
  // 本地缓存的StreamObserver最大实例数
  "stream.observer.max.size": 10000,
  // 本地缓存的Callback最大实例数
  "callback.max.size": 1000,
  // 弹性连接的连接数,按照服务者数量的百分比进行计算
  "consumer.connect.elastic.precent": 0,
  // 弹性连接的连接数
  "consumer.connect.elastic.size": 5,
  /*-------------Consumer相关配置结束-------------*/


  /*-------------异步队列相关配置开始-------------*/
  // 默认回调线程池最小
  "async.pool.core": 10,
  // 默认回调线程池最大
  "async.pool.max": 200,
  // 默认回调线程池队列
  "async.pool.queue": 256,
  //  默认回调线程池回收时间
  "async.pool.time": 60000,
  /*-------------异步队列相关配置结束-------------*/


  /*-------------Transport层相关配置开始-------------*/
  // 使用epoll
  "transport.use.epoll": false,
  //默认数据包大小 8*1024*1024
  "transport.payload.max": 8388608,
  // 客户端io线程数,默认 max(4,cpu+1)
  "transport.client.io.threads": 0,
  // 即I/O操作和用户自定义任务的执行时间比为1:1
  "transport.client.io.ratio": 50,
  "transport.server.backlog": 35536,
  "transport.server.reuseAddr": true,
  "transport.server.keepAlive": true,
  "transport.server.tcpNoDelay": true,
  "transport.server.io.ratio": 50,
  // boss线程,默认max(4,cpu/2)
  "transport.server.boss.threads": 0,
  // 服务端IO线程 max(8,cpu+1)
  "transport.server.io.threads": 0,
  // 最大长连接
  //"transport.server.max.connection" : 65536,
  // 是否允许telnet
  //"transport.server.telnet" : true,
  // 是否守护线程,true随主线程退出而退出,false需要主动退出
  //"transport.server.daemon" : true,
  // 线程方法模型
  "transport.server.dispatcher": "",
  // 是否一个端口支持多协议
  "transport.server.protocol.adaptive": true,
  // buffer默认大小
  "transport.buffer.size": 8192,
  // 写入的buffer水位最大值
  "transport.buffer.max": 32768,
  // 写入的buffer水位最小值
  "transport.buffer.min": 1024,
  // 是否跨接口长链接复用
  "transport.connection.reuse": true,
  // 是否开启压缩
  "compress.open": false,
  // 开启压缩的大小基线
  "compress.size.baseline": 2048,
  //Whether the Http2 Cleartext protocol client uses Prior Knowledge to start Http2
  "transport.client.h2c.usePriorKnowledge": true,
  /*-------------Transport层相关配置结束-------------*/

  /*
   *其它 TODO
   */
  //  Consumer调用时是否发生信息  boolean  默认true,服务端拿到调用端的自动部署应用信息。配为false,服务端拿不到调用者信息  1.6.0
  "invoke.send.app": false,
  //  序列化时是否检查父子类(声明参数和传入值是父子类)  boolean  默认true,如果业务不存在这种情况可以配置为false,提高性能  1.0.0
  "serialize.check.class": false,
  //  序列化是否检测循环引用类型  string  默认true,针对c++等调用者进行关闭  1.6.0
  "serialize.check.reference": false,
  //  客户端是否使用epoll(针对linux)  boolean  默认false,Linux开启epoll可提高性能  1.0.3
  "transport.consumer.epoll": false,
  // 是否检测系统时间,需要filter配合
  "check.system.time": false,
  //计数器服务调用步长  int  默认1,每次丢调用计数器,调大可以提高性能但会减低精准  1.2.0
  "counter.batch": false,
  //json序列化是否返回null字段。  boolean  默认false,默认只返回有属性的字段。打开会降低效率。  1.5.1
  "json.serialize.fill.empty": false,
  //  consumer的服务端列表是否可被清空  boolean  默认false,默认不能被清空(最后的清空请求被忽略),防止删全部节点等误操作,但是会影响列表的准确性。  1.6.0
  "consumer.provider.nullable": false,
  //  json序列化的时候,开启的特性  string  默认空,参见fastjson.serializer.SerializerFeature,多个逗号分隔  1.6.0
  "json.serializer.features": false,
  //  json解析的时候,开启的特性  string  默认空,参见fastjson.parser.Feature,多个逗号分隔  1.6.0
  "json.parser.features": false,
  // 心跳在IO线程吗? TODO
  "transport.heart.io": true,
  // 协商请求在IO线程执行吗? TODO
  "transport.negotiator.async": false,
  //是否所有客户端共享一个重连线程
  "consumer.share.reconnect.thread": false,
  //是否禁止开启lookout采集信息
  "lookout.collect.disable": false
}

把json数据转换成map,保存到全局配置中

/**
 * 全部配置
 */
private final static ConcurrentMap<String, Object>                  CFG          = new ConcurrentHashMap<String, Object>();

// .....

Map map = JSON.parseObject(json, Map.class);
CFG.putAll(map);

下面说 loadCustom("sofa-rpc/rpc-config.json");

/**
     * 加载自定义配置文件
     *
     * @param fileName 文件名
     * @throws IOException 加载异常
     */
    private static void loadCustom(String fileName) throws IOException {
        ClassLoader classLoader = ClassLoaderUtils.getClassLoader(RpcConfigs.class);
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources(fileName)
            : ClassLoader.getSystemResources(fileName);
        if (urls != null) { // 可能存在多个文件
            List<CfgFile> allFile = new ArrayList<CfgFile>();
            while (urls.hasMoreElements()) {
                // 读取每一个文件
                URL url = urls.nextElement();
                InputStreamReader input = null;
                BufferedReader reader = null;
                try {
                    input = new InputStreamReader(url.openStream(), "utf-8");
                    reader = new BufferedReader(input);
                    StringBuilder context = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        context.append(line).append("\n");
                    }
                    Map map = JSON.parseObject(context.toString(), Map.class);
                    Integer order = (Integer) map.get(RpcOptions.RPC_CFG_ORDER);
                    allFile.add(new CfgFile(url, order == null ? 0 : order, map));
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                    if (input != null) {
                        input.close();
                    }
                }
            }
            Collections.sort(allFile, new OrderedComparator<CfgFile>()); // 从小到大排下序
            for (CfgFile file : allFile) {
                CFG.putAll(file.getMap()); // 顺序加载,越大越后加载
            }
        }
    }

 

加载的 sofa-rpc/rpc-config.json 存在于如下位置 :

下面说 loadCustom("META-INF/sofa-rpc/rpc-config.json");

默认没有文件加载到全局配置文件中。

RpcConfigs 类初始化线束!!!!!


回到  RpcRuntimeContext 类的初始化:

static {
        
        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"));
        }
    }

先说 初始化一些上下文:简单的几个上下文属性从RpcConfig配置中读取设置;

初始化其它模块 开始:

/**
     * 加载全部模块
     */
    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 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.");
                }
            }
        }
    }

ExtensionLoader<Module> loader = ExtensionLoaderFactory.getExtensionLoader(Module.class); 开始

/**
   * 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) {
        ExtensionLoader<T> loader = LOADER_MAP.get(clazz);
        if (loader == null) {
            synchronized (ExtensionLoaderFactory.class) {
                loader = LOADER_MAP.get(clazz);
                if (loader == null) {
                    // 关键代码行!!!!
                    loader = new ExtensionLoader<T>(clazz, listener);
                    LOADER_MAP.put(clazz, loader);
                }
            }
        }
        return loader;
    }

关键看上面代码中的 ExtensionLoaderFactory类中: 

loader = new ExtensionLoader<T>(clazz, listener);

ExtensionLoader类:
/**
     * @param path path必须以/结尾
     */
    protected synchronized void loadFromFile(String path) {
        
        // 默认如果不指定文件名字,就是接口名
        String file = StringUtils.isBlank(extensible.file()) ? interfaceName : extensible.file().trim();
        String fullFileName = path + file;
        try {
            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);
            }
        }
    }

下面进入关键代码行:

loadFromClassLoader(classLoader, fullFileName);

protected void loadFromClassLoader(ClassLoader classLoader, String fullFileName) throws Throwable {
        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();
                    }
                }
            }
        }
    }


上面第一个路径 META-INF/services/sofa-rpc/ 配置模块module加载完成,下面同样进入第2个路径 META-INF/services/ 中加载模块,

默认是没有module加载的!

protected void readLine(URL url, String line) {
        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) {
            // ...
            return;
        }
        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 = 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);
        }
    }

 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;
    }
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);
        }
    }

 

ExtensionLoader<Module> loader = ExtensionLoaderFactory.getExtensionLoader(Module.class); 结束!!!

 

下面回到 加载全部模块方法:


/**
     * 加载全部模块
     */
    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 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.");
                }
            }
        }
    }

上面 FaultToleranceModule 类是 上面一个具体的Module配置,

上面是 FaultToleranceModule 类中 定义的 Regulator 实例初始化。上面 module.install()方法:

 

然后就是各个模块的 install()方法运行!!!


初始化其它模块 结束!!!

 


最后回到

下面进入 destroy(false) 方法中:

 /**
     * 销毁方法
     *
     * @param active 是否主动销毁
     */
    private static void destroy(boolean active) {
        // TODO 检查是否有其它需要释放的资源
        RpcRunningState.setShuttingDown(true);
        for (Destroyable.DestroyHook destroyHook : DESTROY_HOOKS) {
            destroyHook.preDestroy();
        }
        List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
        for (ProviderBootstrap bootstrap : EXPORTED_PROVIDER_CONFIGS) {
            providerConfigs.add(bootstrap.getProviderConfig());
        }
        // 先反注册服务端
        List<Registry> registries = RegistryFactory.getRegistries();
        if (CommonUtils.isNotEmpty(registries) && CommonUtils.isNotEmpty(providerConfigs)) {
            for (Registry registry : registries) {
                registry.batchUnRegister(providerConfigs);
            }
        }
        // 关闭启动的端口
        ServerFactory.destroyAll();
        // 关闭发布的服务
        for (ProviderBootstrap bootstrap : EXPORTED_PROVIDER_CONFIGS) {
            bootstrap.unExport();
        }
        // 关闭调用的服务
        for (ConsumerBootstrap bootstrap : REFERRED_CONSUMER_CONFIGS) {
            ConsumerConfig config = bootstrap.getConsumerConfig();
            if (!CommonUtils.isFalse(config.getParameter(RpcConstants.HIDDEN_KEY_DESTROY))) { // 除非不让主动unrefer
                bootstrap.unRefer();
            }
        }
        // 关闭注册中心
        RegistryFactory.destroyAll();
        // 关闭客户端的一些公共资源
        ClientTransportFactory.closeAll();
        // 卸载模块
        if (!RpcRunningState.isUnitTestMode()) {
            ModuleFactory.uninstallModules();
        }
        // 卸载钩子
        for (Destroyable.DestroyHook destroyHook : DESTROY_HOOKS) {
            destroyHook.postDestroy();
        }
        // 清理缓存
        RpcCacheManager.clearAll();
        RpcRunningState.setShuttingDown(false);
      
    }

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值