Dubbo源码学习(一):dubbo如何检查重复的jar包和获取当前dubbo版本号

hi,乡亲们好:

菜鸟最近打算学习一下dubbo背后的实现,但又不知道从哪里看起。幸好有位大牛提供了思路。于是就有了第一篇文章,后续还会更新哒!

一、提出疑问:

(1).Dubbo是利用什么来检查项目中是否出现重复的jar包

(2).Dubbo又是如何来获取项目中的dubbo版本号呢?

  • 带着这两个疑问首先找到代码的入口:在dubbo-config子工程中的org.apache.dubbo.config.spring.schema包中的DubboNamespaceHandler类中的静态代码块中,而该类又继承了spring-bean的NamespaceHandlerSupport,至于为什么要集成它,下一篇文章再陈述。

    //防痴设计来检查是否有重复的jar包 @link:https://blog.csdn.net/youling_lh/article/details/11829779
    static {
    Version.checkDuplicate(DubboNamespaceHandler.class);
    }

  • 在Version类中,主要的两个方法分别是:getVersion(Class<> cls, String defaultVersion)和checkDuplicate(String path, boolean failOnError)

    getVersion(Class<?> cls, String defaultVersion)
    checkDuplicate(String path, boolean failOnError)

(3).先说一下checkDuplicate(String path, boolean failOnError)这个方法实现,该方法就是检查是否存在重复的jar包:

  •   首先将Version这个类作为唯一的标识,获取项目中的Version这个类的文件路径,然后再新建一个SET集合,将获取到的路径放判断是否还有更多的节点,如果有则获取下一个节点,当节点不为空时;再将url对象放入set集合中;为什么要这么做,因为项目中如果出现了重复的jar包,那么就会出现两个Version类,而实际正确情况只能有一个jar包。当两个jar包在不同的路径时,放入不可重复,不能为空的set集合中,如果set的size大于1则说明有重复的jar包。以下是实现的代码:
    

    /**
    * 获取dubbo的版本和检查是否有重复的类,检查是否存在重复的jar包
    * @param path
    * @param failOnError
    */
    public static void checkDuplicate(String path, boolean failOnError) {
    try {
    Enumeration urls = ClassHelper.getCallerClassLoader(Version.class).getResources(path);
    Set files = new HashSet();
    while (urls.hasMoreElements()) {
    URL url = urls.nextElement();
    if (url != null) {
    String file = url.getFile();
    if (file != null && file.length() > 0) {
    files.add(file);
    }
    }
    }
    // duplicated jar is found
    if (files.size() > 1) {
    String error = "Duplicate class " + path + " in " + files.size() + " jar " + files;
    if (failOnError) {
    throw new IllegalStateException(error);
    } else {
    logger.error(error);
    }
    }
    } catch (Throwable e) {
    logger.error(e.getMessage(), e);
    }
    }

  • Enumeration接口中定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素。

  • 大家可以自己在本地测试一下:

    @Test
    public void getFile() throws Exception {
    Enumeration urls = ClassHelper.getCallerClassLoader(JsonResult.class).getResources(JsonResult.class.getName().replace(’.’, ‘/’) + “.class”);
    System.out.println(“urls is {}”+JSON.toJSONString(urls));
    }

    输出的是:urls is {}[“file:/Users/zjc/Documents/github-sources/springboot-mybatis/target/classes/com/zjc/springboot/common/JsonResult.class”]

(4).然后说一下getVersion(Class<> cls, String defaultVersion)这个方法实现,该方法就是获取dubbo的版本号:

  • 首先是查找MANIFEST.MF规范中的版本号,如果这时候得到了版本号则会直接返回当前的版本号;如果规范中没有版本号则会基于jar包名获取版本号。如果这时也没有获取到版本号,则会返回默认的版本号为"";如果获取到了则会得到jar包的路径path,判断path是否以".jar"结尾,然后根据lastIndexOf()和indexOf()方法,得出版本号(jar包一般是项目名,加上一个“-”,后面再加上数字版本号),一下是实现的代码:

    public static String getVersion(Class<?> cls, String defaultVersion) {
    try {
    // find version info from MANIFEST.MF first
    // 先从MANIFEST.MF文件中的版本号 jar文件中必然存在MANIFEST.MF文件;
    String version = cls.getPackage().getImplementationVersion();
    if (version == null || version.length() == 0) {
    //此方法返回执行的版本
    version = cls.getPackage().getSpecificationVersion();
    }

            if (version == null || version.length() == 0) {
                // guess version fro jar file name if nothing's found from MANIFEST.MF
                CodeSource codeSource = cls.getProtectionDomain().getCodeSource();
    
                if (codeSource == null) {
                    logger.info("No codeSource for class " + cls.getName() + " when getVersion, use default version " + defaultVersion);
                } else {
                    //得到jar文件
                    String file = codeSource.getLocation().getFile();
                        if (file != null && file.length() > 0 && file.endsWith(".jar")) {
    
                            file = file.substring(0, file.length() - 4);
                            int i = file.lastIndexOf('/');
                            if (i >= 0) {
                                file = file.substring(i + 1);
                            }
                            i = file.indexOf("-");
                            if (i >= 0) {
                                file = file.substring(i + 1);
                            }
                            while (file.length() > 0 && !Character.isDigit(file.charAt(0))) {
                                i = file.indexOf("-");
                                if (i >= 0) {
                                    file = file.substring(i + 1);
                                } else {
                                    break;
                                }
                            }
                            version = file;
                        }
                }
            }
            // return default version if no version info is found
            return version == null || version.length() == 0 ? defaultVersion : version;
        } catch (Throwable e) {
            // return default version when any exception is thrown
            logger.error("return default version, ignore exception " + e.getMessage(), e);
            return defaultVersion;
        }
    }
    

Version类中除了当前这两个方法,其它都是些辅助的方法,在这里不做过多的解释。下一篇将学习一下,Dubbo是如何来解析XMl配置文件的,是如何寻找注册中心、服务提供者、服务消费者功能入口。也就是说为什么前面说DubboNamespaceHandler继承NamespaceHandlerSupport;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值