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())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值