RocketMQ源码解析(3)

RocketMq源码解析 (三)

这一期还是接着分析MixAll这个类的功能

object2Porperties(final Object object)

    public static Properties object2Porperties(final Object object){
        Properties properties=new Properties();
        Field[] fields=object.getClass().getDeclaredFields();
        for(Field field:fields){
            if(Modifier.isStatic(field.getModifiers())){
                String name=field.getName();
                if(!name.startsWith("this")){
                    Object value=null;
                    try {
                        field.setAccessible(true);
                        value=field.get(object);
                    }catch (IllegalArgumentException | IllegalAccessException e){
                        e.printStackTrace();
                    }

                    if(value!=null){
                        properties.setProperty(name,value.toString());
                    }
                }
            }
        }
        return properties;
    }

在上一期的基础上,这一段就很容易理解了,把对象的静态字段且不是以this开头的装换为Properties,例如

String static IsOpen="test"

转换后就变成了key-value的形式,原理上一期已经解释过了。进入下一个函数

properties2Object(final Properties properties,final Object object)

 /**
     * 将参数注入到类的set方法中,完成参数的初始化
     * @param properties
     * @param object
     */
    public static void properties2Object(final Properties properties,final Object object) {
        Method[] methods = object.getClass().getMethods();
        for (Method method : methods) {
            String mn = method.getName();
            if (mn.startsWith("set")) {
                try {
                    //判断是否以set开头
                    String tmp = mn.substring(4);
                    String first = mn.substring(3, 4);
                    //setArgs转换为args
                    String key = first.toLowerCase() + tmp;

                    String property = properties.getProperty(key);
                    if (property != null) {
                        //获取方法的参数列表
                        Class<?>[] pt = method.getParameterTypes();
                        if (pt != null && pt.length > 0) {
                            //第一个参数,
                            String cn = pt[0].getSimpleName();
                            Object arg = null;
                            if (cn.equals("int") || cn.equals("Integer")) {
                                arg = Integer.parseInt(property);
                            } else if (cn.equals("long") || cn.equals("Long")) {
                                arg = Long.parseLong(property);
                            } else if (cn.equals("double") || cn.equals("Double")) {
                                arg = Double.parseDouble(property);
                            } else if (cn.equals("boolean") || cn.equals("Boolean")) {
                                arg = Boolean.parseBoolean(property);
                            } else if (cn.equals("float") || cn.equals("Float")) {
                                arg = Float.parseFloat(property);
                            } else if (cn.equals("String")) {
                                arg = property;
                            } else {
                                continue;
                            }
                            method.invoke(object, arg);
                        }
                    }
                } catch (Throwable ignored) {
                }
            }
        }
    }

这个方法的作用很明显,把属性注入到对应的对象中,一个对象中的属性值我们都回提供set方法来注入属性,我们只要把所有set开头的方法
提取出来即可,object.getClass().getMethods(); 则是用到了java的反射机制,把对象的所有
方法放到Method对象里,我们看看这个方法到返回了什么
在这里插入图片描述而且还有没有显示声明,从父类继承而来的方法,比如notify等,而set标准写法为setProperties(),对应的属性名为properties,这也是语言规范,故需要大小写转换,接着获取对应方法的参数列表。如图,会显示方法所有的参数,对于set方法来说只有一个参数,且参数类型应当和字段类型相同,
在这里插入图片描述
至于getSimpleName 我们看看源码

        int length = simpleName.length();
        int index = 1;
        while (index < length && isAsciiDigit(simpleName.charAt(index)))
            index++;
        // Eventually, this is the empty string iff this is an anonymous class
        return simpleName.substring(index);
    }

不难发现就是返回最后一个 . 后面的字符串,自然就是我们需要的属性类型,然后就是把参数中key(属性名)对应的值类型转换为字段需要的类型从而进行注入,这里不难发现转换只支持五大基本数据类型和对应的包装类加上String,说明注入的都是一些基本类型。最后就是invoke了这也是java反射机制中一个强大的功能,这里是吧object中对应的method参数注入为arg并执行,想要深入了解可以看一看java反射之Method的invoke方法实现,其详细解释了其实现原理。

getLocalInetAddress()

 /**
     * 判断两个属性对象是否相等
     * @param p1 属性1
     * @param p2 属性2
     * @return 是否相等
     */
    public static boolean isPropertiesEqual(final Properties p1, final Properties p2) {
        return p1.equals(p2);
    }

    /**
     * 获取本机的网络地址
     * @return 本机网络地址
     */
    public static List<String> getLocalInetAddress(){
        List<String> inetAddressList=new ArrayList<String>();
        try {
            //获取本机所有的网络接口
            Enumeration<NetworkInterface> enumeration=NetworkInterface.getNetworkInterfaces();
            while(enumeration.hasMoreElements()){
                NetworkInterface networkInterface=enumeration.nextElement();
                Enumeration<InetAddress> addres=networkInterface.getInetAddresses();
                while (addres.hasMoreElements()){
                    //主机名传入
                    inetAddressList.add(addres.nextElement().getHostName());
                }
            }
        }catch (SocketException e){
            throw new RuntimeException("get local inet Address fail",e);
        }
        return inetAddressList;
    }
        /**
     * 判断是否为本机地址
     * @param address 网络地址
     * @return
     */
    public static boolean isLocalAddr(String address){
        for(String addr:LOCAL_INET_ADDRESS){
            if(address.contains(addr)){
                return true;
            }
        }
        return false;
    }

这里用到了NetworkInterface.getNetworkInterfaces() 用来获取机器上所有的网络接口,在本机上执行结果如下,估计是把虚拟网络接口也算进去了。作用暂时未知。
在这里插入图片描述
后续则是一个判断是否为本机地址的函数,作用未知。

compareAndIncreaseOnly(final AtomicLong target,final long value)

    /**
     * 确保target只能增长
     * @param target 目标
     * @param value 值
     * @return 是否增长
     */
    public static boolean compareAndIncreaseOnly(final AtomicLong target,final long value){
        long prev=target.get();
        while (value > prev){
            boolean update=target.compareAndSet(prev,value);
            if(update){
                return true;
            }
            prev=target.get();
        }
        return false;
    }

这个函数用来确保target只能增长的,这里解决了CAS的一个漏洞,也就是ABA问题,确保增长的情况下ABA问题则不存在。

获取本机地址,这里不再详细介绍

    /**
     * 获取本机地址
     * @return 机器名
     */
    public static String localhost(){
        try {
            return InetAddress.getLocalHost().getHostName();
        }catch (UnknownHostException e){
            throw new RuntimeException("InetAddress java.net.InetAddress.getLocalHost() throws UnknownHostException"
                    + FAQURL.suggestTodo(FAQURL.UNKNOWN_HOST_EXCEPTION),
                    e);
        }
    }

humanReadableByteCount(long bytes,boolean si)

/**
     * 把字节数装换为可以读懂的单位,
     * @param bytes 字节数
     * @param si 单位为1000还是1024
     * @return
     */
    public static String humanReadableByteCount(long bytes,boolean si){
        int unit = si ? 1000 : 1024;
        if (bytes < unit)
            return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(unit));
        String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
        return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
    }

这里有一个细节,形参的修饰符没有final了,所以应该不是同一个人写的,而这个作用也很明显,就是把字节转换成合适的单位。有几个细节需要注意一个是大小写k,然后就是kiB和kB,这是国际上关于计算机单位的问题,事实上1kB=1000byte 1KiB=1024byte,有时候表达严谨而是用kiB单位。

list2Set(List< String > values)

 /**
     * list装换为set
     * @param values
     * @return
     */
    public Set<String> list2Set(List<String> values) {
        Set<String> result = new HashSet<String>();
        for (String v : values) {
            result.add(v);
        }
        return result;
    }

    /**
     * set装换为list
     * @param values
     * @return
     */
    public List<String> set2List(Set<String> values) {
        List<String> result = new ArrayList<String>();
        for (String v : values) {
            result.add(v);
        }
        return result;
    }

这两个没什么好说的,两种类型的装换。
至此,MixAll的所有函数分析完毕,大概的印象应该有了,具体功能差不多也知道了,就是把配置文件类似于XML这样的进行类的初始化,就像tomcat配置文件一样,而联系MixAll这个类名,不难想象可能是把所有的相关文件装配到系统中,具体我们下一期将对这个类进行测试。分析其可以改进的地方。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RocketMQ NameServer 是 RocketMQ 的一个核心组件,主要负责管理 RocketMQ 集群中的各个 Broker 节点的信息,包括 Broker 的名称、IP 地址、状态等信息。在 RocketMQ 集群中,所有的 Broker 都需要向 NameServer 注册,以便 NameServer 能够掌握整个集群的状态信息。 RocketMQ NameServer 的源码位于 `rocketmq-namesrv` 模块中,其主要实现了以下功能: 1. 启动时加载配置文件,包括监听端口、存储路径、集群名称等信息; 2. 处理 Broker 节点的注册、注销请求,维护 Broker 节点的状态信息; 3. 处理 Consumer 节点的心跳请求,维护 Consumer 节点的状态信息; 4. 处理 Topic 的创建、删除请求,维护 Topic 的状态信息; 5. 提供查询 Broker 节点、Topic 等信息的接口。 RocketMQ NameServer 的核心类是 `NamesrvController`,它继承了 Netty 的 `NettyRemotingServer` 类,并实现了 `RequestProcessor` 接口,用于处理来自 Broker 和 Consumer 节点的请求。在 `NamesrvController` 中,还包含了 `RouteInfoManager`、`BrokerHousekeepingService`、`KVConfigManager` 等组件,用于维护集群状态信息和管理配置文件。 RocketMQ NameServer 的启动入口是 `main` 方法,它会加载配置文件并启动 `NamesrvController`。启动后,NameServer 会监听指定端口,等待来自 Broker 和 Consumer 节点的请求,并根据请求类型调用相应的处理方法进行处理。 总之,RocketMQ NameServer 的主要作用是管理整个 RocketMQ 集群的状态信息,确保集群中各个节点的状态始终保持同步。其源码实现比较复杂,需要深入理解 RocketMQ 的设计思想和架构原理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值