Skip to content

配置加载

字数: 0 字 时长: 0 分钟

需求分析

RPC 框架在运行过程中会涉及到很多的配置信息,比如注册中心的地址、序列化方式、网络服务器端口等,因此我们需要一套全局配置加载功能,能够让 RPC 框架轻松从配置文件中读取配置。

在实现之前,我们先来了解一下业界标杆 Spring 是如何实现实现配置资源的加载和维护的。

Spring配置加载.webp

Spring 使用 Environment 抽象接口来统一管理全局配置,它作为一个逻辑上的全局环境变量环境,整合了所有配置源(application 配置文件、系统变量、JNDI等),为整个应用提供一致的配置访问入口。

上面我列出了 Spring 环境变量模块的部分类图,实际上整个模块很复杂,涉及到了大量的设计模式,这里我们实现的简易 RPC 框架参照 Spring 配置模块简单实现即可。

1. 全局配置类

Spring 的 Environment 接口下有各种环境的具体实现,这里我们就简单创建一个标准环境的配置类 RpcConfig 即可。

2. 配置加载器

Spring 定义了 PropertyResolver 接口,下面有不同配置源的加载实现,这里我们创建一个 ConfigUtils 工具类作为我们的配置加载器。

3. 配置访问入口

Spring 使用 Environment 抽象接口作为配置访问入口,我们创建一个 RpcApplication 类作为统一的配置访问入口即可。

代码实现

  • RpcConfig 全局配置对象类
java
/**
 * RPC 框架配置
 */
@Data
public class RpcConfig {

    /**
     * 名称
     */
    private String name = "t-rpc";

    /**
     * 版本号
     */
    private String version = "1.0";

    /**
     * 服务器主机名
     */
    private String serverHost = "localhost";

    /**
     * 服务器端口号
     */
    private Integer serverPort = 8080;

    /**
     * 是否需要启动 server
     */
    private boolean needServer = false;

    /**
     * 模拟调用
     */
    private boolean mock = false;

    /**
     * 序列化器
     */
    private String serializer = SerializerKeys.JDK;

    /**
     * 注册中心配置
     */
    private RegistryConfig registryConfig = new RegistryConfig();

    /**
     * 负载均衡器
     */
    private String loadBalancer = LoadBalancerKeys.ROUND_ROBIN;

}
  • ConfigUtils 配置加载工具类
java
/**
 * 配置工具类
 */
public class ConfigUtils {

    public static <T> T loadConfig(Class<T> tClass,String prefix) {
        return loadConfig(tClass,prefix,"");
    }

    public static <T> T loadConfig(Class<T> tClass,String prefix,String environment) {
        StringBuilder configFileBuilder = new StringBuilder("application");
        if (StrUtil.isNotBlank(environment)) {
            configFileBuilder.append("-").append(environment);
        }
        configFileBuilder.append(".properties");
        Props props = new Props(configFileBuilder.toString());
        return props.toBean(tClass,prefix);
    }

}
  • RpcApplication 类作为 RPC 框架配置访问入口

这里我们对全局配置对象 RpcConfig 使用单例模式实现,不用每次使用配置时都重新读取配置并创建对象,减少性能开销。

java
@Slf4j
public class RpcApplication {

    private static volatile RpcConfig rpcConfig;

    /**
     * 框架初始化,支持传入自定义配置
     * @param newRpcConfig
     */
    public static void init(RpcConfig newRpcConfig) {
        rpcConfig = newRpcConfig;
        log.info("RpcApplication init...,config = {}",newRpcConfig.toString());
    }

    /**
     * 初始化
     */
    public static void init() {
        RpcConfig newRpcConfig;
        try {
            newRpcConfig = ConfigUtils.loadConfig(RpcConfig.class, RpcConstant.DEFAULT_CONFIG_PREFIX);
        }catch (Exception e) {
            newRpcConfig = new RpcConfig();
        }
        init(newRpcConfig);
    }

    /**
     * 获取配置
     * @return
     */
    public static RpcConfig getRpcConfig() {
        if (rpcConfig == null) {
            synchronized (RpcApplication.class) {
                if (rpcConfig == null) {
                    init();
                }
            }
        }
        return rpcConfig;
    }

}
  • application.properties 配置文件

根据编写的 RpcConfig 类和配置加载工具类,我们就可以像 Spring 一样从 application.properties 文件中读取配置了。不过现在只能读取 properties 格式文件的,并且在 RpcConfig 中定义的配置项,后续可以考虑扩展,像 Spring 那样可以读取 yml 格式的配置文件

application.properties 文件

properties
rpc.name=t-rpc
rpc.version=2.0
rpc.serverPort=8081
rpc.serializer=kryo