外观
外观
1355字约5分钟
2024-05-18
在 RPC 框架运行的过程中,会涉及到很多的配置信息,比如注册中心的地址、序列化方式、网络服务器端口号等等。
之前的简易版 RPC 项目中,对这些配置进行硬编码,不利于维护。
而且 RPC 框架是需要被其他项目作为服务提供者或者服务消费者引入的,我们应当允许引入框架的项目通过编写配置文件来自定义配置。并且一般情况下,服务提供者和服务消费者需要编写相同的 RPC 配置。
因此,需要实现一套全局配置加载功能。能够让 RPC 框架轻松地从配置文件中读取配置,并且维护一个全局配置对象,便于框架快速获取到一致的配置。
常见的 RPC 框架配置项如下:
目前只使用以下几个配置:
读取配置文件可以使用 Java的 Properties 类自行编写,但是更推荐使用一些第三方工具库,比如 Hutool 的 Setting 模块,可以直接读取指定名称的配置文件中的部分配置信息,并且转换成 Java 对象,非常方便。
在 config 包下新建配置类 Rpcconfig ,用于保存配置信息。
@Data
public class RpcConfig {
/**
* 名称
*/
private String name = "honghu-rpc";
/**
* 版本号
*/
private String version = "1.0";
/**
* 服务器主机名
*/
private String serverHost = "localhost";
/**
* 服务器端口号
*/
private Integer serverPort = 8080;
}
在 utis 包下新建工具类 configutils ,作用是读取配置文件并返回配置对象,可以简化调用,工具类应当尽量通用,和业务不强绑定,提高使用的灵活性。比如支持外层传入要读取的配置内容前缀、支持传入环境等。
public class ConfigUtils {
/**
* 加载配置对象
*
* @param tClass
* @param prefix
* @return
* @param <T>
*/
public static <T> T loadConfig(Class<T> tClass, String prefix){
return loadConfig(tClass,prefix,"");
}
/**
* 加载配置对象,支持区分环境
*
* @param tClass
* @param prefix
* @param environment
* @return
* @param <T>
*/
public static <T> T loadConfig(Class<T> tClass, String prefix,String environment){
StringBuilder configFileBulider = new StringBuilder("application");
if(StrUtil.isNotBlank(environment)){
configFileBulider.append("-").append(environment);
}
configFileBulider.append(".properties");
Props props = new Props(configFileBulider.toString());
return props.toBean(tClass,prefix);
}
}
在 constant 包中新建 Rpcconstant 接囗,用于存储 RPC 框架相关的常量
public interface RpcConstant {
/**
* 默认配置文件加载前缀
*/
String DEFAULT_CONFIG_PREFIX = "rpc";
}
RPC框架中雲要维护一个全局的配置对象。在引入 RPC 框架的项目启动时,从配置文件中读取配置并创建对象实例,之后就可以集中地从这个对象中获取配置信息,而不用每次加载配置时再重新读取配置、并创建新的对象,减少了性能开销。
使用设计模式中的 单例模式,就能够很轻松地实现这个需求。
使用RpcApplication 类作为 RPC 项目的启动入口、并且维护项目全局用到的变量。
@Slf4j
public class RpcApplication {
private static volatile RpcConfig rpcConfig;
/**
* 框架初始化,支持传入自定义配置
*
* @param newRpcConfig
*/
public static void init(RpcConfig newRpcConfig){
rpcConfig = newRpcConfig;
log.info("rpc 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;
}
}
这里采用了双检锁单例模式,支持在获取配置时才调用 init 方法实现懒加载。为了便于扩展,还支持自己传入配置对象;如果不传入,则默认调用前面写好的 Configutils 来加载配置。以后 RPC 框架内只需要写一行代码,就能正确加载到配置:
RpcConfig rpcConfig = RpcApplication.getRpcConfig();