全局配置加载
- 通过读取配置文件来进行加载配置项
执行流程
- 1.加载全局配置并初始化RPC框架
- 2.注册服务
- 3.启动HTTP服务器,等待请求
- 4.通过加载全局配置并初始化rpc框架获取代理对象并调用代理对象的方法
- 5.指定序列化器,构造RPC Request
- 6.将请求序列化为字节数组,发送HTTP请求
- 7.等待接收HTTP响应
- 8.通过web服务器监听并接收consumer的请求
- 9.经过请求处理器将请求反序列化RPC Request
- 10.使用本地服务注册器查询 provider 中的对应服务并进行反射调用
- 11.将 provider 返回的结果构造为RPC Response,并将RPC Response序列化为字节数组
- 12.rpc发送HTTP响应
- 13.consumer接收响应
- 14.consumer将响应反序列化为RPC Request
- 15.consumer获取响应中的结果
1.项目初始化
1.1 引入依赖
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.12</version>
</dependency>
1.2 修改依赖
1.2.1 修改服务提供者依赖
<dependency>
<!-- RPC 框架 -->
<groupId>com.todaysaturday</groupId>
<artifactId>todaysaturday-rpc-core1.0</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
1.2.2 修改服务消费者依赖
<dependency>
<!-- RPC 框架 -->
<groupId>com.todaysaturday</groupId>
<artifactId>todaysaturday-rpc-core1.0</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.配置加载
2.1 创建配置类(RpcConfig)
/**
* RPC 框架配置
*/
@Data
public class RpcConfig {
/**
* 名称
*/
private String name = "todaysaturday-rpc";
/**
* 版本号
*/
private String version = "1.0";
/**
* 服务器主机名
*/
private String serverHost = "localhost";
/**
* 服务器端口号
*/
private Integer serverPort = 8080;
}
2.2 创建工具类(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>
*/
private static <T> T loadConfig(Class<T> tClass, String prefix, String environment) {
StringBuilder configFileBuilder = new StringBuilder("application");
if(StrUtil.isNotBlank(environment)){
configFileBuilder.append("-").append(environment);// 追加环境标识,比如dev等
}
configFileBuilder.append(".properties");
// 加载配置文件
Props props = new Props(configFileBuilder.toString());
// 解析为Java对象
T result = props.toBean(tClass, prefix);
return result;
}
}
2.3 创建常量类(RpcConstant)
/**
* Rpc 相关常量
*/
public class RpcConstant {
/**
* 默认配置文件加载前缀
*/
public static final String DEFAULT_CONFIG_PREFIX = "rpc";
}
2.4 创建启动类(RpcApplication)
/**
* Rpc 框架应用
* 相当于holder,存放了项目全局用到的变量,双检锁单例模式实现
* 支持在获取配置时才调用 init 方法实现懒加载。
*/
@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;
}
}
2.5 创建配置文件
application.propertes
rpc.name=todaysaturdayrpc
rpc.version=2.0
rpc.serverPort=8081
2.6 修改代理实现类
- 这里如果不修改,就还是走的默认端口8080
// 从配置中取值进行拼接URI
Integer serverPort = RpcApplication.getRpcConfig().getServerPort();
String serverHost = RpcApplication.getRpcConfig().getServerHost();
String url = "http://"+serverHost +":" +serverPort;
// 4.发出HTTP请求
try(HttpResponse httpResponse = HttpRequest.post(url)
.body(bodyBytes)
.execute()){
result = httpResponse.bodyBytes();
}
3.扩展
3.0 新增yaml/yml
application.yml
rpc:
name: todaysaturdayrpc-yaml
version: 3.0
serverPort: 8082
application.yaml
rpc:
name: todaysaturdayrpc-yaml
version: 4.0
serverPort: 8083
3.1 引入依赖
<!--支持解析yaml和yml文件-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.15.2</version>
</dependency>
3.2 修改RpcConstant
/**
* 解析 YAML 的 ObjectMapper
*/
public static final com.fasterxml.jackson.databind.ObjectMapper YAML_MAPPER = new com.fasterxml.jackson.databind.ObjectMapper(new YAMLFactory());
3.3 修改ConfigUtils
/**
* 加载配置对象,支持区分环境,支持yaml和yml文件。
* @param tClass
* @param prefix
* @param environment
* @return
* @param <T>
*/
private static <T> T loadConfig(Class<T> tClass, String prefix, String environment,String configFileExtension) {
StringBuilder configFileBuilder = new StringBuilder("application");
if(StrUtil.isNotBlank(environment)){
configFileBuilder.append("-").append(environment);// 追加环境标识,比如dev等
}
T result = null;
if(!StrUtil.isEmpty(configFileExtension)){
if("yaml".equals(configFileExtension) || "yml".equals(configFileExtension)){
String fullConfigPath = configFileBuilder.toString();
// 获取 src/main/resource 路径下的文件
try(InputStream inputStream = ConfigUtils.class.getClassLoader().getResourceAsStream(fullConfigPath +"."+configFileExtension)){
if(inputStream !=null){
JsonNode rootNode = YAML_MAPPER.readTree(inputStream);
JsonNode prefixedNode = rootNode.path(prefix);
result = YAML_MAPPER.treeToValue(prefixedNode, tClass);
System.out.println(result.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}else{
configFileBuilder.append(".properties");
// 加载配置文件
Props props = new Props(configFileBuilder.toString());
// 解析为Java对象
result = props.toBean(tClass, prefix);
}
return result;
}
3.4 修改服务提供者
/**
* 简易服务提供者示例
*/
public class EasyProviderExample {
public static void main( String[] args ){
RpcConfig rpcConfig = ConfigUtils.loadConfig(RpcConfig.class, "rpc", "", "yaml");
// RPC 框架初始化
RpcApplication.init(rpcConfig);
System.out.println("RpcProvider:"+RpcApplication.getRpcConfig());
// 注册服务
LocalRegistry.register(UserService.class.getName(), UserServiceImpl.class);
// 启动 web 服务
VertxHttpServer httpServer = new VertxHttpServer();
httpServer.doStart(RpcApplication.getRpcConfig().getServerPort());
}
}
3.5 修改服务消费者
/**
* 服务消费者启动类
*
*/
public class EasyConsumerExample {
public static void main( String[] args ){
// 加载配置文件
RpcConfig rpcConfig = ConfigUtils.loadConfig(RpcConfig.class, "rpc", "", "yaml");
RpcApplication.init(rpcConfig);
System.out.println("RpcConsumer:"+RpcApplication.getRpcConfig());
// 创建静态代理
// UserService userService = new UserServiceProxy();
// 创建JDK动态代理
UserService userService = JdkServiceProxyFactory.getProxy(UserService.class);
// 创建CGlib动态代理
// UserService userService = CGlibServiceProxyFactory.getProxy(UserService.class);
User user = new User();
user.setName("todaysaturday");
User newUser = userService.getUser(user);
if(newUser == null){
System.out.println("user == null");
}else{
System.out.println("user == "+ newUser.getName());
}
}
}