1、SOFA RPC 源码解析 —— 服务发布篇

有一阵子没有更新源码解析了,最近关注了一个微服务框架SOFA RPC这是蚂蚁金服的一个开源框架,地址在:https://github.com/sofastack/sofa-rpc, 这个框架还是一个朋友推荐的,看了第一部分它的发布流程没想到代码写的很精简易懂,封装性也很好,更大的激发了我看它的乐趣,那我们就一起一步步去学习下它的整个微服务框架的构成和实现吧!

一、 首先我们先从github fork下SOFA RPC这个项目,作者使用的是5.5版本,环境搭建及整体模型介绍参考:https://www.jianshu.com/p/1eeee833bd5d, 本地编译好那就准备工作都完成了,开始分析吧!服务发布现在有两种方式,一种是SOFA RPC发布方式,还有一种是使用SOFA BOOT,本系列文章都使用SOFA RPC方式分析,SOFA BOOT我们后面开专栏讲解是怎么封装SPRING BOOT的,OK 贴发布代码:


/** 需要发布的接口
**/
public interface HelloService {

    public String sayHello(String name);
}
/** 发布接口的实现类
**/
public class HelloServiceImpl implements HelloService {

    public String sayHello(String name) {
        return "hello , "+name;
    }
}
/** SOFA RPC 发布流程
**/
public class RpcServer {
    public static void main(String[] args) {
        //1、 构建RegistryConfig 注册配置
        RegistryConfig registryConfig = new RegistryConfig().setProtocol("sofa").setAddress("127.0.0.1:8080");
        RegistryConfig registryConfig1 = new RegistryConfig().setProtocol("zookeeper").setAddress("127.0.0.1:2181");
        List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
        registryConfigs.add(registryConfig);
        registryConfigs.add(registryConfig1);
        // 2、构建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);
        // 3、构建发布配置
        ProviderConfig<HelloService> providerConfig = new ProviderConfig<HelloService>()
                .setApplication(new ApplicationConfig()
                .setAppName("paul"))
                .setInterfaceId(HelloService.class.getName())
                .setRef(new HelloServiceImpl())
                .setServer(serverConfigs)
                .setRegistry(registryConfig);
        // 4、正式发布
        providerConfig.export();
    }
}

前面接口类和实现类我们不必要多说,我们主要讲它怎么发布的,那我们进一步看下发布流程做了哪几件事
1、构建RegistryConfig 注册配置

      RegistryConfig registryConfig = new RegistryConfig().setProtocol("sofa").setAddress("127.0.0.1:8080");
      RegistryConfig registryConfig1 = new RegistryConfig().setProtocol("zookeeper").setAddress("127.0.0.1:2181");
      List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();

首先是构建RegistryConfig注册配置,这个主要是用来注册服务使用的,可以支持多个协议:

文中举例使用了sofa 和 zookeeper 的注册中心,我们点进去源码发现是这样的:

public class RegistryConfig extends AbstractIdConfig implements Serializable
    ...

发现它是空构造方法,那它真的什么都没做吗?不是!它继承了AbstractIdConfig这个类,我们点进去这个类是这样的:

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

这里我们就发现了,它有一个静态方法,那我们看看这个静态方法干了些什么:
这个也是啥都没做但是我们又发现RpcRuntimeContext又有一个静态方法,点进去看看,终于在这里我们看到它还是做了些事的

static {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Welcome! Loading SOFA RPC Framework : {}, PID is:{}", Version.BUILD_VERSION, PID);
        }
        // 放入当前的sofa版本号
        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"));
        }
    }

那我们来一步步看看这个到底做了些什么
首先是 放入当前的sofa版本号,这个没啥说的,都是写死的版本,其次是初始化一些上下文,这里就是设置了全局运行时上下文类RpcRuntimeContext首先初始化上下文自动部署的appId、appName、appInsId以及当前所在文件夹地址appPath信息:

    /**
     * 初始化一些上下文
     */
    private static void initContext() {
        putIfAbsent(KEY_APPID, RpcConfigs.getOrDefaultValue(APP_ID, null));
        putIfAbsent(KEY_APPNAME, RpcConfigs.getOrDefaultValue(APP_NAME, null));
        putIfAbsent(KEY_APPINSID, RpcConfigs.getOrDefaultValue(INSTANCE_ID, null));
        putIfAbsent(KEY_APPAPTH, System.getProperty("user.dir"));
    }

其中通过配置加载器和操作入口RpcConfigs静态代码块在类加载的时候加载rpc-config-default.json、sofa-rpc/rpc-config.json、META-INF/sofa-rpc/rpc-config.json配置文件获取默认配置、自定义配置信息自定义配置信息存储在全部配置CFG:

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

接下来就是初始化其它模块了,这个模块我简单写了两个注释,这个不影响阅读,因为里面涉及到SPI,为减少篇幅,会单独写一篇文章来介绍

    /**
     * 加载全部模块
     */
    public static void installModules() {
    	// 使用ExtensionLoaderFactory获取传入class的ExtensionLoader
        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.");
                }
            }
        }
    }

接下来是增加jvm关闭事件了,这里面涉及到优雅停机,篇幅较大,后续我补充一篇优雅停机的文章

     // 增加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"));
     }

2、讲到这里我们的构建RegistryConfig 注册配置就讲完啦,接下来是构建ServerConfig 服务配置,这个主要是服务发布的协议配置,支持多种协议,比如说rest、bolt、等

我们点进源码会发现实际上它是跟前面我们讲的RegistryConfig是继承的同一个类,那我们这里就不赘述了,进入下一步构建发布配置,这个代码相对简单,主要就是将前面两步的配置放进ProviderConfig,那我们就愉快的进入最后一步,也是这篇文章的重点:服务发布!

 // 4、正式发布
 providerConfig.export();
 /**
  * 发布服务
  */
 public synchronized void export() {
     if (providerBootstrap == null) {
     	// 获取执行的 providerBootstrap 
        providerBootstrap = Bootstraps.from(this);
     }
     // 使用获取的 providerBootstrap 执行发布
     providerBootstrap.export();
 }
     /**
     * 发布一个服务
     *
     * @param providerConfig 服务发布者配置
     * @param <T>            接口类型
     * @return 发布启动类
     */
    public static <T> ProviderBootstrap<T> from(ProviderConfig<T> providerConfig) {
    	// 如果我们没有设置bootstrap那就会使用默认的bootstrap
        String bootstrap = providerConfig.getBootstrap();
        if (StringUtils.isEmpty(bootstrap)) {
            // Use default provider bootstrap,read from rpcconfigs,默认是 sofa
            bootstrap = RpcConfigs.getStringValue(RpcOptions.DEFAULT_PROVIDER_BOOTSTRAP);
            providerConfig.setBootstrap(bootstrap);
        }
        //获取执行的 export providerBootstrap默认是DefaultProviderBootstrap,这里有SPI的东西,等我补了直接看那篇文章即可
        ProviderBootstrap providerBootstrap = ExtensionLoaderFactory.getExtensionLoader(ProviderBootstrap.class)
            .getExtension(bootstrap, new Class[] { ProviderConfig.class }, new Object[] { providerConfig });
        return (ProviderBootstrap<T>) providerBootstrap;
    }
    // DefaultProviderBootstrap里面的export()方法
	@Override
    public void export() {
        if (providerConfig.getDelay() > 0) { // 延迟加载,单位毫秒
            Thread thread = factory.newThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(providerConfig.getDelay());
                    } catch (Throwable ignore) { // NOPMD
                    }
                    doExport();
                }
            });
            thread.start();
        } else {
            doExport();
        }
    }
    private void doExport() {
    	// 已经发布则直接retrurn
        if (exported) {
            return;
        }
        // 检查参数
        checkParameters();
        // 设置发布应用名称,比如我的设置就是 setApplication(new ApplicationConfig().setAppName("paul"))
        String appName = providerConfig.getAppName();
        //key  is the protocol of server,for concurrent safe
        Map<String, Boolean> hasExportedInCurrent = new ConcurrentHashMap<String, Boolean>();
        // 将处理器注册到server
        List<ServerConfig> serverConfigs = providerConfig.getServer();
        for (ServerConfig serverConfig : serverConfigs) {
            String protocol = serverConfig.getProtocol();

            String key = providerConfig.buildKey() + ":" + protocol;

            if (LOGGER.isInfoEnabled(appName)) {
                LOGGER.infoWithApp(appName, "Export provider config : {} with bean id {}", 
                        key, providerConfig.getId());
            }

            // 注意同一interface,同一uniqueId,不同server情况
            AtomicInteger cnt = EXPORTED_KEYS.get(key); // 计数器
            if (cnt == null) { // 没有发布过
                cnt = CommonUtils.putToConcurrentMap(EXPORTED_KEYS, key, new AtomicInteger(0));
            }
            int c = cnt.incrementAndGet();
            hasExportedInCurrent.put(serverConfig.getProtocol(), true);
            int maxProxyCount = providerConfig.getRepeatedExportLimit();
            if (maxProxyCount > 0) {
                if (c > maxProxyCount) {
                    decrementCounter(hasExportedInCurrent);
                    // 超过最大数量,直接抛出异常
                    throw new SofaRpcRuntimeException("Duplicate provider config with key " + key
                        + " has been exported more than " + maxProxyCount + " times!"
                        + " Maybe it's wrong config, please check it."
                        + " Ignore this if you did that on purpose!");
                } else if (c > 1) {
                    if (LOGGER.isInfoEnabled(appName)) {
                        LOGGER.infoWithApp(appName, "Duplicate provider config with key {} has been exported!"
                            + " Maybe it's wrong config, please check it."
                            + " Ignore this if you did that on purpose!", key);
                    }
                }
            }

        }

        try {
            // 构造请求调用器
            providerProxyInvoker = new ProviderProxyInvoker(providerConfig);
            // 初始化注册中心
            if (providerConfig.isRegister()) {
                List<RegistryConfig> registryConfigs = providerConfig.getRegistry();
                if (CommonUtils.isNotEmpty(registryConfigs)) {
                    for (RegistryConfig registryConfig : registryConfigs) {
                        RegistryFactory.getRegistry(registryConfig); // 提前初始化Registry
                    }
                }
            }
            // 将处理器注册到server
            for (ServerConfig serverConfig : serverConfigs) {
                try {
                    Server server = serverConfig.buildIfAbsent();
                    // 注册请求调用器
                    server.registerProcessor(providerConfig, providerProxyInvoker);
                    if (serverConfig.isAutoStart()) {
                        server.start();
                    }

                } catch (SofaRpcRuntimeException e) {
                    throw e;
                } catch (Exception e) {
                    LOGGER.errorWithApp(appName, "Catch exception when register processor to server: "
                        + serverConfig.getId(), e);
                }
            }

            // 注册到注册中心
            providerConfig.setConfigListener(new ProviderAttributeListener());
            register();
        } catch (Exception e) {
            decrementCounter(hasExportedInCurrent);

            if (e instanceof SofaRpcRuntimeException) {
                throw (SofaRpcRuntimeException) e;
            } else {
                throw new SofaRpcRuntimeException("Build provider proxy error!", e);
            }
        }

        // 记录一些缓存数据
        RpcRuntimeContext.cacheProviderConfig(this);
        exported = true;
    }

我们先看看他主要做了哪些事情:
1、检查参数和方法
2、将处理器保存到ConcurrentMap
3、构造请求调用器,初始化注册中心
4、将处理器注册到server,注册请求调用器,注册到注册中心
5、记录一些缓存数据
开始分析:
1、检查参数和方法

    /**
     * for check fields and parameters of consumer config
     */
    protected void checkParameters() {
        // 检查注入的ref是否接口实现类
        Class proxyClass = providerConfig.getProxyClass();
        // key = interfaceId + CFG 默认配置的 uniqueId (为空)
        String key = providerConfig.buildKey();
        T ref = providerConfig.getRef();
        // 自身类.class.isInstance(自身实例或子类实例) 才返回true
        if (!proxyClass.isInstance(ref)) {
            throw ExceptionUtils.buildRuntime("provider.ref",
                    ref == null ? "null" : ref.getClass().getName(),
                    "This is not an instance of " + providerConfig.getInterfaceId()
                            + " in provider config with key " + key + " !");
        }
        // server 不能为空
        if (CommonUtils.isEmpty(providerConfig.getServer())) {
            throw ExceptionUtils.buildRuntime("server", "NULL", "Value of \"server\" is not specified in provider" +
                    " config with key " + key + " !");
        }
        checkMethods(proxyClass);
    }
        /**
     * Gets proxy class.
     *
     * @return the proxyClass
     */
    @Override
    public Class<?> getProxyClass() {
        if (proxyClass != null) {
            return proxyClass;
        }
        try {
        	// 如果设置的interfaceId不为空
            if (StringUtils.isNotBlank(interfaceId)) {
            	// 反射拿到代理类
                this.proxyClass = ClassUtils.forName(interfaceId);
                if (!proxyClass.isInterface()) {
                    throw ExceptionUtils.buildRuntime("service.interfaceId",
                        interfaceId, "interfaceId must set interface class, not implement class");
                }
            } else {
                throw ExceptionUtils.buildRuntime("service.interfaceId",
                    "null", "interfaceId must be not null");
            }
        } catch (SofaRpcRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SofaRpcRuntimeException(e.getMessage(), e);
        }
        return proxyClass;
    }
    /**
     * 检查方法,例如方法名、多态(重载)方法
     *
     * @param itfClass 接口类
     */
    protected void checkMethods(Class<?> itfClass) {
        ConcurrentHashMap<String, Boolean> methodsLimit = new ConcurrentHashMap<String, Boolean>();
        // 获取代理类以及父类或者父接口中所有的公共方法(public修饰符修饰的)
        for (Method method : itfClass.getMethods()) {
            String methodName = method.getName();
            // 重载的方法会提示warn,sofa rpc不建议一个服务里使用多个同名方法
            if (methodsLimit.containsKey(methodName)) {
                // 重名的方法
                if (LOGGER.isWarnEnabled(providerConfig.getAppName())) {
                    LOGGER.warnWithApp(providerConfig.getAppName(), "Method with same name \"" + itfClass.getName()
                        + "." + methodName + "\" exists ! The usage of overloading method in rpc is deprecated.");
                }
            }
            // 判断服务下方法的黑白名单
            Boolean include = methodsLimit.get(methodName);
            if (include == null) {
            	// 检查是否在黑白名单中,黑白名单这两个都是在配置文件配置的
                include = inList(providerConfig.getInclude(), providerConfig.getExclude(), methodName); 
                methodsLimit.putIfAbsent(methodName, include);
            }
        }
        providerConfig.setMethodsLimit(methodsLimit);
    }

2、将处理器保存到ConcurrentMap

    List<ServerConfig> serverConfigs = providerConfig.getServer();
    for (ServerConfig serverConfig : serverConfigs) {
    	// 获取发布协议,比如我们就配置了bolt 和rest 两个协议
        String protocol = serverConfig.getProtocol();
        // key = interfaceId + uniqueId + ":" + protocol
        String key = providerConfig.buildKey() + ":" + protocol;
        if (LOGGER.isInfoEnabled(appName)) {
            LOGGER.infoWithApp(appName, "Export provider config : {} with bean id {}", key, providerConfig.getId());
        }
        // 注意同一interface,同一uniqueId,不同server情况
        AtomicInteger cnt = EXPORTED_KEYS.get(key); // 计数器
        if (cnt == null) { // 没有发布过
            cnt = CommonUtils.putToConcurrentMap(EXPORTED_KEYS, key, new AtomicInteger(0));
        }
        // 原子性自增
        int c = cnt.incrementAndGet();
        // 将发布过的协议放入hasExportedInCurrent
        hasExportedInCurrent.put(serverConfig.getProtocol(), true);
        // 获取最大可重复发布数,读取配置文件的,默认是 1
        int maxProxyCount = providerConfig.getRepeatedExportLimit();
        if (maxProxyCount > 0) {
            if (c > maxProxyCount) {
            	// 超过最大数量,decrementCounter,里面就是将EXPORTED_KEYS.get(key)大于0的decrementAndGet
                decrementCounter(hasExportedInCurrent);
                // 超过最大数量,直接抛出异常
                throw new SofaRpcRuntimeException("Duplicate provider config with key " + key
                    + " has been exported more than " + maxProxyCount + " times!"
                    + " Maybe it's wrong config, please check it."
                    + " Ignore this if you did that on purpose!");
            } else if (c > 1) {
                if (LOGGER.isInfoEnabled(appName)) {
                    LOGGER.infoWithApp(appName, "Duplicate provider config with key {} has been exported!"
                        + " Maybe it's wrong config, please check it."
                        + " Ignore this if you did that on purpose!", key);
                }
            }
        }
    }

3、构造请求调用器,初始化注册中心
4、将处理器注册到server,注册请求调用器,注册到注册中心
5、记录一些缓存数据
这三点我们放一起讲吧:

    try {
        // 构造请求调用器
        providerProxyInvoker = new ProviderProxyInvoker(providerConfig);
        // 初始化注册中心
        if (providerConfig.isRegister()) {
            List<RegistryConfig> registryConfigs = providerConfig.getRegistry();
            if (CommonUtils.isNotEmpty(registryConfigs)) {
                for (RegistryConfig registryConfig : registryConfigs) {
                    RegistryFactory.getRegistry(registryConfig); // 提前初始化Registry
                }
            }
        }
        // 将处理器注册到server
        for (ServerConfig serverConfig : serverConfigs) {
            try {
                Server server = serverConfig.buildIfAbsent();
                // 注册请求调用器
                server.registerProcessor(providerConfig, providerProxyInvoker);
                if (serverConfig.isAutoStart()) {
                    server.start();
                }
            } catch (SofaRpcRuntimeException e) {
                throw e;
            } catch (Exception e) {
                LOGGER.errorWithApp(appName, "Catch exception when register processor to server: "
                    + serverConfig.getId(), e);
            }
        }
        // 注册到注册中心
        providerConfig.setConfigListener(new ProviderAttributeListener());
        register();
    } catch (Exception e) {
    	// 捕获异常先对发布服务数decrement一下
        decrementCounter(hasExportedInCurrent);
        if (e instanceof SofaRpcRuntimeException) {
            throw (SofaRpcRuntimeException) e;
        } else {
            throw new SofaRpcRuntimeException("Build provider proxy error!", e);
        }
    }
    // 记录一些缓存数据
    RpcRuntimeContext.cacheProviderConfig(this);
    exported = true;

首先来看下构造请求调用器

    /**
     * 构造执行链
     *
     * @param providerConfig 服务端配置
     */
    public ProviderProxyInvoker(ProviderConfig providerConfig) {
        this.providerConfig = providerConfig;
        // 最底层是调用过滤器
        this.filterChain = FilterChain.buildProviderChain(providerConfig,
            new ProviderInvoker(providerConfig));
    }

我们就来看下最底层是调用过滤器这里做了些什么:

  /**
     * Instantiates a new Provider invoke filter.
     *
     * @param providerConfig the provider config
     */
    public ProviderInvoker(ProviderConfig<T> providerConfig) {
    	// 调用父类构造方法
        super(providerConfig);
        this.providerConfig = providerConfig;
    }
        /**
     * 如果无需下一层过滤器
     *
     * @param config 过滤器所在的接口配置
     */
    protected FilterInvoker(AbstractInterfaceConfig config) {
        this.config = config;
        if (config != null) {
            this.configContext = config.getConfigValueCache(false);
        }
    }
    /**
     * 接口属性和方法属性加载配置到缓存
     *
     * @param rebuild 是否重建
     * @return Map<String Object> unmodifiableMap
     */
    public synchronized Map<String, Object> getConfigValueCache(boolean rebuild) {
    	// 第一次进来 configValueCache 是空的
        if (configValueCache != null && !rebuild) {
            return configValueCache;
        }
        Map<String, Object> context = new HashMap<String, Object>(32);
        // providerParams 也是空的
        Map<String, String> providerParams = getParameters();
        if (providerParams != null) {
            context.putAll(providerParams); // 复制接口的自定义参数
        }
       	// methodConfigs 也是空的
        Map<String, MethodConfig> methodConfigs = getMethods();
        if (CommonUtils.isNotEmpty(methodConfigs)) {
            for (MethodConfig methodConfig : methodConfigs.values()) {
                String prefix = RpcConstants.HIDE_KEY_PREFIX + methodConfig.getName() 
                    + RpcConstants.HIDE_KEY_PREFIX;
                Map<String, String> methodparam = methodConfig.getParameters();
                if (methodparam != null) { // 复制方法级自定义参数
                    for (Map.Entry<String, String> entry : methodparam.entrySet()) {
                        context.put(prefix + entry.getKey(), entry.getValue());
                    }
                }
                // 复制方法级参数属性
                BeanUtils.copyPropertiesToMap(methodConfig, prefix, context);
            }
        }
        // 复制接口级参数属性,可以看出第一次初始化时直接把providerConfig的属性配置都赋值到了context上
        BeanUtils.copyPropertiesToMap(this, StringUtils.EMPTY, context);
        // 这里的configValueCache 的值实际上就是providerConfig的,并且使用unmodifiableMap保存
        configValueCache = Collections.unmodifiableMap(context);
        return configValueCache;
    }

然后就只剩下这个方法啦:FilterChain.buildProviderChain(providerConfig,new ProviderInvoker(providerConfig));点进去

 /**
     * 构造服务端的执行链
     *
     * @param providerConfig provider配置
     * @param lastFilter     最后一个filter
     * @return filter执行链
     */
    public static FilterChain buildProviderChain(ProviderConfig<?> providerConfig, FilterInvoker lastFilter) {
        return new FilterChain(selectActualFilters(providerConfig, PROVIDER_AUTO_ACTIVES), lastFilter, providerConfig);
    }
    
    /**
     * 获取真正的过滤器列表
     *
     * @param config            provider配置或者consumer配置
     * @param autoActiveFilters 系统自动激活的过滤器映射
     * @return 真正的过滤器列表
     */
    private static List<Filter> selectActualFilters(AbstractInterfaceConfig config,
                                                    Map<String, ExtensionClass<Filter>> autoActiveFilters) {
        /*
         * 例如自动装载扩展 A(a),B(b),C(c)  filter=[-a,d]  filterRef=[new E, new Exclude(b)]
         * 逻辑如下:
         * 1.解析config.getFilterRef(),记录E和-b
         * 2.解析config.getFilter()字符串,记录 d 和 -a,-b
         * 3.再解析自动装载扩展,a,b被排除了,所以拿到c,d
         * 4.对c d进行排序
         * 5.拿到C、D实现类
         * 6.加上自定义,返回C、D、E
         */
        // 用户通过自己new实例的方式注入的filter,优先级高
        List<Filter> customFilters = config.getFilterRef() == null ?
            new ArrayList<Filter>() : new CopyOnWriteArrayList<Filter>(config.getFilterRef());
        // 先解析是否有特殊处理
        HashSet<String> excludes = parseExcludeFilter(customFilters);

        // 准备数据:用户通过别名的方式注入的filter,需要解析
        List<ExtensionClass<Filter>> extensionFilters = new ArrayList<ExtensionClass<Filter>>();
        List<String> filterAliases = config.getFilter(); //
        if (CommonUtils.isNotEmpty(filterAliases)) {
            for (String filterAlias : filterAliases) {
                if (startsWithExcludePrefix(filterAlias)) { // 排除用的特殊字符
                    excludes.add(filterAlias.substring(1));
                } else {
                    ExtensionClass<Filter> filter = EXTENSION_LOADER.getExtensionClass(filterAlias);
                    if (filter != null) {
                        extensionFilters.add(filter);
                    }
                }
            }
        }
        // 解析自动加载的过滤器,配了-*和-default表示不加载内置
        if (!excludes.contains(StringUtils.ALL) && !excludes.contains(StringUtils.DEFAULT)) {
            for (Map.Entry<String, ExtensionClass<Filter>> entry : autoActiveFilters.entrySet()) {
                if (!excludes.contains(entry.getKey())) {
                    extensionFilters.add(entry.getValue());
                }
            }
        }
        // 按order从小到大排序
        if (extensionFilters.size() > 1) {
            Collections.sort(extensionFilters, new OrderedComparator<ExtensionClass<Filter>>());
        }
        List<Filter> actualFilters = new ArrayList<Filter>();
        for (ExtensionClass<Filter> extensionFilter : extensionFilters) {
            actualFilters.add(extensionFilter.getExtInstance());
        }
        // 加入自定义的过滤器
        actualFilters.addAll(customFilters);
        return actualFilters;
    }

这个获取filterchain注释写的比较清楚,我这里就不再补充了,看下一段

   // 初始化注册中心
   if (providerConfig.isRegister()) {
   		// 获取我们配置的registryConfigs 
       List<RegistryConfig> registryConfigs = providerConfig.getRegistry();
       if (CommonUtils.isNotEmpty(registryConfigs)) {
           for (RegistryConfig registryConfig : registryConfigs) {
           		// 提前初始化Registry
               RegistryFactory.getRegistry(registryConfig); 
           }
       }
   }
      /**
    * 得到注册中心对象
    *
    * @param registryConfig RegistryConfig类
    * @return Registry实现
    */
   public static synchronized Registry getRegistry(RegistryConfig registryConfig) {
       if (ALL_REGISTRIES.size() > 3) { // 超过3次 是不是配错了?
           if (LOGGER.isWarnEnabled()) {
               LOGGER.warn("Size of registry is greater than 3, Please check it!");
           }
       }
       try {
           // 注意:RegistryConfig重写了equals方法,如果多个RegistryConfig属性一样,则认为是一个对象
           Registry registry = ALL_REGISTRIES.get(registryConfig);
           if (registry == null) {
           		// spi 根据配置的协议找对应的扩展类加载,这里会加载所有的Registry扩展类 sofa,zookeeper
               ExtensionClass<Registry> ext = ExtensionLoaderFactory.getExtensionLoader(Registry.class)
                   .getExtensionClass(registryConfig.getProtocol());
               if (ext == null) {
                   throw ExceptionUtils.buildRuntime("registry.protocol", registryConfig.getProtocol(),
                       "Unsupported protocol of registry config !");
               }
               // 实例化扩展类
               registry = ext.getExtInstance(new Class[] { RegistryConfig.class }, new Object[] { registryConfig });
               // 放入ALL_REGISTRIES供后面register使用
               ALL_REGISTRIES.put(registryConfig, registry);
           }
           return registry;
       } catch (SofaRpcRuntimeException e) {
           throw e;
       } catch (Throwable e) {
           throw new SofaRpcRuntimeException(e.getMessage(), e);
       }
   }

下一段:

    // 将处理器注册到server
    for (ServerConfig serverConfig : serverConfigs) {
        try {
        	// 循环构建server
            Server server = serverConfig.buildIfAbsent();
            // 注册请求调用器
            server.registerProcessor(providerConfig, providerProxyInvoker);
            if (serverConfig.isAutoStart()) {
                server.start();
            }

        } catch (SofaRpcRuntimeException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.errorWithApp(appName, "Catch exception when register processor to server: "
                    + serverConfig.getId(), e);
        }
    }
     /**
     * 启动服务
     *
     * @return the server
     */
    public synchronized Server buildIfAbsent() {
        if (server != null) {
            return server;
        }
        // 提前检查协议+序列化方式
        // ConfigValueHelper.check(ProtocolType.valueOf(getProtocol()),
        //                SerializationType.valueOf(getSerialization()));
		// 使用serverFactory初始化server
        server = ServerFactory.getServer(this);
        return server;
    }
    /**
     * 初始化Server实例
     *
     * @param serverConfig 服务端配置
     * @return Server
     */
    public synchronized static Server getServer(ServerConfig serverConfig) {
        try {
            Server server = SERVER_MAP.get(Integer.toString(serverConfig.getPort()));
            if (server == null) {
                // 绑定网卡和端口,下面有详细分析
                resolveServerConfig(serverConfig);
                // SPI加载server扩展类,比如说BoltServer,RestServer
                ExtensionClass<Server> ext = ExtensionLoaderFactory.getExtensionLoader(Server.class)
                    .getExtensionClass(serverConfig.getProtocol());
                if (ext == null) {
                    throw ExceptionUtils.buildRuntime("server.protocol", serverConfig.getProtocol(),
                        "Unsupported protocol of server!");
                }
                // 获取server实例
                server = ext.getExtInstance();
                // 初始化server,这里面主要是初始化业务线程池和初始化配置协议的ServerProcessor,比如我们用bolt协议就是         
                // BoltServer 和 BoltServerProcessor
                server.init(serverConfig);
                SERVER_MAP.put(serverConfig.getPort() + "", server);
            }
            return server;
        } catch (SofaRpcRuntimeException e) {
            throw e;
        } catch (Throwable e) {
            throw new SofaRpcRuntimeException(e.getMessage(), e);
        }
    }
    /**
     * 确定下Server的host和port
     *
     * @param serverConfig 服务器配置
     */
    private static void resolveServerConfig(ServerConfig serverConfig) {
        // 绑定到指定网卡 或全部网卡
        String boundHost = serverConfig.getBoundHost();
        // 我们没有配置boundHost 
        if (boundHost == null) {
        	// 我们也没配置host
            String host = serverConfig.getHost();
            if (StringUtils.isBlank(host)) {
            	// 获取系统本地host
                host = SystemInfo.getLocalHost();
                serverConfig.setHost(host);
                // windows绑定到0.0.0.0的某个端口以后,其它进程还能绑定到该端口
                boundHost = SystemInfo.isWindows() ? host : NetUtils.ANYHOST;
            } else {
                boundHost = host;
            }
            serverConfig.setBoundHost(boundHost);
        }
        // 绑定的端口
        if (serverConfig.isAdaptivePort()) {
            int oriPort = serverConfig.getPort();
            int port = NetUtils.getAvailablePort(boundHost, oriPort,
                RpcConfigs.getIntValue(RpcOptions.SERVER_PORT_END));
            if (port != oriPort) {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("Changed port from {} to {} because the config port is disabled", oriPort, port);
                }
                serverConfig.setPort(port);
            }
        }
    }
    接下来就是
    // 注册请求调用器,BoltServer
   server.registerProcessor(providerConfig, providerProxyInvoker);
   
   @Override
   public void registerProcessor(ProviderConfig providerConfig, Invoker instance) {
      	// 获取唯一名字key
        String key = ConfigUniqueNameGenerator.getUniqueName(providerConfig);
         // 缓存Invoker对象
        invokerMap.put(key, instance);
		// 放入回收失效缓存中
        ReflectCache.registerServiceClassLoader(key, providerConfig.getProxyClass().getClassLoader());
        // 缓存接口的方法,这里主要是将每个代理接口的方法和参数缓存起来
        for (Method m : providerConfig.getProxyClass().getMethods()) {
            ReflectCache.putOverloadMethodCache(key, m);
        }
    }
   好了,到下一段:
    if (serverConfig.isAutoStart()) {
         server.start();
     }
    @Override
    public void start() {
        if (started) {
            return;
        }
        synchronized (this) {
            if (started) {
                return;
            }
            // 生成Server对象,这里调用的阿里的另外一个开源框架 SOFA BOLT,传入绑定绑定host和port
            remotingServer = initRemotingServer();
            try {
                if (remotingServer.start()) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Bolt server has been bind to {}:{}", serverConfig.getBoundHost(),
                            serverConfig.getPort());
                    }
                } else {
                    throw 
                        new SofaRpcRuntimeException("Failed to start bolt server, see more detail from bolt log.");
                }
                started = true;
				// 是否开启服务启动消息总线
                if (EventBus.isEnable(ServerStartedEvent.class)) {
                	// 发布f服务启动事件
                    EventBus.post(new ServerStartedEvent(serverConfig, bizThreadPool));
                }

            } catch (SofaRpcRuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new SofaRpcRuntimeException("Failed to start bolt server!", e);
            }
        }
    }

到这里服务发布已经完成,但是我们前面讲了只是初始化注册,提前暴露注册中心的配置或者其他问题,并没有真的注册,那么就到了最后一段代码了:

   // 添加监听器
   providerConfig.setConfigListener(new ProviderAttributeListener());
   // 注册到注册中心
   register();
   
    /**
     * 注册服务
     */
    protected void register() {
        if (providerConfig.isRegister()) {
            List<RegistryConfig> registryConfigs = providerConfig.getRegistry();
            if (registryConfigs != null) {
                for (RegistryConfig registryConfig : registryConfigs) {
                	// 老规矩还是根据registryConfig加载扩展类registry,但是我们上面初始化已经分析了这里就跳过
                    Registry registry = RegistryFactory.getRegistry(registryConfig);
                    // 初始化配置,拿zookeeper打比方就是初始化zkClient,添加认证信息等
                    registry.init();
                    // 连接至zk
                    registry.start();
                    try {
                    	// 注册和订阅服务
                        registry.register(providerConfig);
                    } catch (SofaRpcRuntimeException e) {
                        throw e;
                    } catch (Throwable e) {
                        String appName = providerConfig.getAppName();
                        if (LOGGER.isWarnEnabled(appName)) {
                            LOGGER.warnWithApp(appName, "Catch exception when register to registry: "
                                + registryConfig.getId(), e);
                        }
                    }
                }
            }
        }
    }

SOFARPC服务发布流程概括为SOFARPC服务需要创建服务运行容器配置ServerConfig,自定义设置基础配置并且通过配置文件加载服务端默认配置;创建服务发布配置ProviderConfig,自定义设置接口名称、接口实现类引用以及指定服务端配置;服务发布启动类ProviderBootstrap发布服务:构造请求调用器ProviderProxyInvoker(最底层调用过滤器执行链FilterChain),提前初始化注册中心,创建服务端Server包括启动业务线程池bizThreadPool 、创建BoltServerProcessor处理器,服务端Server注册服务提供者配置ProviderConfig、服务端调用实现ProviderProxyInvoker,服务端Server启动服务创建RpcServer,将BoltServerProcessor处理器缓存到userProcessors,初始化服务启动ServerBootstrap,根据userProcessors创建RpcHandler处理器添加到ChannelPipeline,创建RPC服务连接完成启动服务链路。RPC服务请求调用RpcHandler的channelRead()方法获取UserProcessor执行handlerRequest()方法查找服务调用器Invoker实施调用过滤器执行链FilterChain方法调用。

posted @ 2019-08-14 14:25  paul丶  阅读(626)  评论(0编辑  收藏  举报