yaml文件解析工具
在common包下创建YamlReader
要解析yaml文件,我们需要使用一个外部库
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
</dependency>
工具需要扫描application.yml文件,并且解析文件提取出我们需要的配置。
我们自定义配置 rpcConfig
rpcConfig:
port: 9001
packageName: com.suancaiyu.ServiceImpl
registerCenter:
port: 6379
host: localhost
我们需要使用一个实体对象来表示这个配置
在common包下创建对象RpcConfig
package com.suancaiyu.rpc_common.common.model.entity.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RpcConfig{
private String port;
private String packageName;
@Override
public String toString() {
return "RpcConfig{" +
"port='" + port + ''' +
", packName='" + packageName + ''' +
", registerCenter=" + registerCenter +
'}';
}
private RegisterCenter registerCenter;
}
我们还需要一个RegisterCenter
package com.suancaiyu.rpc_common.common.model.entity.config;
public class RegisterCenter {
private String port;
private String host;
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
@Override
public String toString() {
return "RegisterCenter{" +
"port='" + port + ''' +
", host='" + host + ''' +
'}';
}
public RegisterCenter() {
}
public RegisterCenter(String port, String host) {
this.port = port;
this.host = host;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
回到YamlReader
package com.suancaiyu.rpc_common.reader;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.suancaiyu.rpc_common.exception.ConfigNotFound;
import com.suancaiyu.rpc_common.exception.ConfigurationFileNotFound;
import com.suancaiyu.rpc_common.common.model.entity.config.RpcConfig;
import com.suancaiyu.rpc_common.util.SerializationUtil;
import org.apache.log4j.Logger;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
public class YamlReader {
private static LinkedHashMap<String, LinkedHashMap<String,Object>> properties;
private static RpcConfig rpcConfig;
private static final Logger logger = Logger.getLogger(YamlReader.class);
private static final String yamlName="application.yml";
private static final String root="rpcConfig";
static {
getYamlMap();
}
public static void getYamlMap(){
InputStream in = null;
try {
Yaml yaml = new Yaml();
in = YamlReader.class.getClassLoader().getResourceAsStream(yamlName);
properties= yaml.loadAs(in,LinkedHashMap.class);
if (properties==null){
throw new ConfigNotFound();
}
LinkedHashMap<String, Object> rpcConfigMap= properties.get(root);
if (rpcConfigMap==null){
throw new ConfigNotFound();
}
rpcConfig = SerializationUtil.convertLinkedHashMap(rpcConfigMap, RpcConfig.class);
} catch (YAMLException e) {
logger.error(yamlName+" not found");
throw new ConfigurationFileNotFound();
} catch (JsonProcessingException e) {
logger.debug(e.getMessage());
e.printStackTrace();
} catch (NullPointerException e){
logger.error(e.getMessage());
}
finally {
try {
if (in!=null){
in.close();
}
} catch (NullPointerException | IOException e) {
e.printStackTrace();
}
}
}
public static RpcConfig getRpcConfig() {
return rpcConfig;
}
// public static String getValueByKey(String key) {
// getYamlMap();
// String value = null;
// if (root.equals(key)) {
// Iterator it = properties.entrySet().iterator();
// while (it.hasNext()) {
// Map.Entry entry = (Map.Entry) it.next();
// if (key.equals(entry.getKey())) {
// value = (String) entry.getValue();
// break;
// }
// }
// } else {
// LinkedHashMap<String, String> rootProperty = (LinkedHashMap<String, String>) properties.get(root);
// value = iter(rootProperty, key);
//
// }
// return value;
// }
// public static String iter(LinkedHashMap<String, String> rootProperty, String key) {
// Iterator it = rootProperty.entrySet().iterator();
// String value = null;
// while (it.hasNext()) {
// Map.Entry entry = (Map.Entry) it.next();
// if (key.equals(entry.getKey())) {
// return (String) entry.getValue();
// }
// if (!(entry.getValue() instanceof LinkedHashMap)) {
// continue;
// }
// value = iter((LinkedHashMap<String, String>) entry.getValue(), key);
// if (value != null) {
// break;
// }
// }
// return value;
// }
}
直接使用外部库解析yaml文件再使用jackson反序列化成rpcConfig对象
redis注册中心
在Rpc_server包下创建OnlineRegister类。
思考这个类的功能应该有哪些
1 注册:注册服务
2 获取服务:从注册中心获取对应服务
3 扫描包路径并且自动注册
4 需要一个redis的客户端,使用jedis作为客户端
5 需要在类加载的时候获取相关的配置
6 扫描包时,我们需要一个注解来区分服务类和非服务类,使用自定义注解@RpcConfig
package com.suancaiyu.rpc_server.register;
import com.suancaiyu.rpc_common.common.model.ExceptionMessage;
import com.suancaiyu.rpc_common.exception.RegisterCenterNotFound;
import com.suancaiyu.rpc_common.exception.ServiceNotFound;
import com.suancaiyu.rpc_server.annotation.RpcService;
import com.suancaiyu.rpc_common.reader.ClassScanner;
import com.suancaiyu.rpc_common.reader.YamlReader;
import redis.clients.jedis.Jedis;
import java.util.List;
public class OnlineRegister {
private static int registerPort;
private static String registerHost;
private static final int servicePort= Integer.parseInt(YamlReader.getRpcConfig().getPort());
private static final String packageName;
private static final String serviceHost="localhost";
static {
try {
registerPort=Integer.parseInt(YamlReader.getRpcConfig().getRegisterCenter().getPort());
registerHost=YamlReader.getRpcConfig().getRegisterCenter().getHost();
packageName=YamlReader.getRpcConfig().getPackageName();
if (registerHost==null){
throw new RegisterCenterNotFound(ExceptionMessage.REGISTERCENTERNOTFOUND);
}
if (packageName==null){
throw new ServiceNotFound(ExceptionMessage.PACKNAMECONFIGNOTFOUND);
}
}catch (NullPointerException e){
throw new RegisterCenterNotFound(ExceptionMessage.REGISTERCENTERNOTFOUND);
}
}
// TODO: 2023/6/24 改善:加入连接池
private static Jedis jedis = null;
private static void getJedis(){
if (jedis==null){
synchronized (OnlineRegister.class){
if (jedis==null){
jedis= new Jedis(registerHost,registerPort);
}
}
}
}
public static void register(String interfaceName,Class<?> implClass){
getJedis();
RpcService annotation = implClass.getAnnotation(RpcService.class);
String version = annotation.value();
String key=serviceHost+":"+servicePort+":"+interfaceName+":"+version;
String implClassName = implClass.getName();
jedis.set(key,implClassName);
}
public static Class<?> get(String interfaceName,String version) throws ClassNotFoundException {
String key=serviceHost+":"+servicePort+":"+interfaceName+":"+version;
String implClassName = jedis.get(key);
return Class.forName(implClassName);
}
public static void scanService() {
try {
List<Class<?>> classList= ClassScanner.getClasses(packageName);
for (Class<?> clazz : classList) {
if (clazz.isAnnotationPresent(RpcService.class)){
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> interfaceClass:interfaces){
String interfaceName = interfaceClass.getName();
register(interfaceName,clazz);
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
注册服务: 我们以服务地址+服务端口号+接口名+版本号作为key值,实现类的全类名作为value值存储进redis之中。
获取服务: 获取到服务类的全类名后使用反射生成该类的Class对象并且返回
包扫描: 扫描具体配置中包名,识别带有@rpcService的类,通过反射拿取相关信息再调用注册服务将服务批量注册进去。
获取相关配置: 使用static静态代码块在类加载时获取相关配置
@RpcService
package com.suancaiyu.rpc_server.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME )
@Documented
@Target(ElementType.TYPE)
public @interface RpcService {
String value() default "1.0";
}