使用redis作为注册中心,以及yaml文件解析工具类

46 阅读3分钟

yaml文件解析工具

在common包下创建YamlReader

image.png

要解析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";
}