• 乙方的烦恼---如何在乙方升级的情况下甲方不用升级?


    故事背景

    自古以来,做买卖、特别是供大于求情况下,市场游戏总会出现乙方有求于甲方的现象。

     在现在的市场经济机制下,甲方和乙方的地位更难平等,小王是深有体会。小王是一家软件外包公司的员工,他们为一家国企提供软件服务,最近小王比较烦,因需求变更,甲方大爷软件中引用的一个jar中的常量发生了变化,他们更新了jar包,但甲方只同意将新jar包替换掉旧的jar包,导致系统出现执行异常!甲方限令必须尽快找到问题并解决掉!

    为了防止公司信息泄露,我们模拟一下这个场景:

    public class BinaryCompatibilityTest {
    
        public static void main(String[] args) {
            System.out.println(DefineConstants.FIRST + " " +
                    DefineConstants.SECOND + " " +
                    DefineConstants.THIRD);
                    }
    }

    其中DefineConstants来自甲方对乙方的引用:

    import com.test.constants.Words;
    
    public class DefineConstants {
        private DefineConstants() { }; // Uninstantiable
        public static final String FIRST = Words.FIRST;
        public static final String SECOND = Words.SECOND;
        public static final String THIRD = Words.THIRD;
    
    }

    其中,Words是引用的公用jar包

     类实现如下:

    package com.test.constants;
    
    public class Words {
        private Words() {
        }; // Uninstantiable
    
        public static final String FIRST = "the";
        public static final String SECOND = null;
        public static final String THIRD = "set";
    }

    原先打印结果为

    the null set

    现在乙方小王修改了jar包后,代码变成了

    package com.test.constants;
    
    public class Words {
        private Words() {
        }; // Uninstantiable
    
        public static final String FIRST = "physics";
        public static final String SECOND = "chemistry";
        public static final String THIRD = "biology";
    }

    他将重新打包后的jar包传给甲方,让甲方在tomcat上替换原来的jar包,结果运行后打印的结果却为:

    the chemistry set

    小王百思不得其解。

     反复确认了jar包是否正确,都是最新的jar包。

    万般无奈之下只好请出被辞退的中老年技术大神"老司机",并答应老司机1w/d的辛苦费。

     老司机了解了情况后,就找到了原因,通过jd-gui反编译了代码给小王看:

     替换了jar包后,DefineConstants并没有被重新编译,导致FIRST和THIRD的结果没有发生改变,

    但因SECOND本身为null,在编译期常量表达式(compile-time constant expression)[JLS15.28]的精确定义中找到。它的定义太长了,就不在这里写出来了,但是理解这

    个程序的行为的关键是null 不是一个编译期常量表达式。运行时就会执行新的结果:chemistry

    解决办法是

    1. 需要重新编译DefineConstants后,替换到新的class

    2.重新编译整个项目的打包文件,提供新的包文件替换旧的打包文件

    第一个方案

       优点: 线上改动小,影响小,速度快

       缺点:只能解决当前问题,如果项目中还有别的地方引用这个变量,将还会出错。

    第二个方案

       优点:从根本上解决问题

       缺点:线上影响稍微大一些。

    小王入司刚两年,是个勤奋好学的家伙,项目搞定后请老司机吃饭喝酒,趁老司机酒醉,趁机问解决这个问题的诀窍,老司机喝迷糊后道出了本质:

    原来java考虑到升级的问题,有二进制兼容性规范,。。。。。。。。。

    因老司机喝的有点多,描述的不是很清楚,小王只记住了在jsl规范了有明确的描述:jsl 13章,https://docs.oracle.com/javase/specs/jls/se12/html/index.html

    参考资料:

    【1】http://blog.sina.com.cn/s/blog_4c408e27010009ae.html

    【2】java解惑

    【3】https://docs.oracle.com/javase/specs/jls/se12/html/index.html

    【4】https://docs.oracle.com/javase/specs/jls/se12/html/jls-15.html#jls-15.28

  • 相关阅读:
    css3(持续更新...)
    em,rem,px之间的转换
    document.compatMode属性
    CSS hack(CSS浏览器兼容)
    JavaScript正则表达式
    Django数据库sqlite转mysql
    Markdown 使用指南
    centos7下docker 部署javaweb
    CMD命令大全
    {dockerUI}在服务器上直接安装shipyard/shipyard
  • 原文地址:https://www.cnblogs.com/davidwang456/p/11601374.html
Copyright © 2020-2023  润新知