一种评估Maven环境中依赖冲突危险级别的方法与流程

文档序号:16247296发布日期:2018-12-11 23:41阅读:207来源:国知局
一种评估Maven环境中依赖冲突危险级别的方法与流程

本发明涉及软件可靠性领域,特别涉及一种评估maven环境中依赖冲突危险级别的方法。

背景技术

在软件开发的过程中,经常会使用第三方开源项目进行软件复用来减少开发成本。apache组织开发维护的maven是用java编写的开源项目的管理工具。使用maven进行项目开发可以通过xml形式的pom文件导入及管理项目的依赖。但是在maven的构建环境中,由于同一个开源项目存在多个版本、maven的依赖管理又存在依赖传递机制,经常会导致项目中出现依赖冲突现象,产生软件缺陷。在软件测试不充分的情况下,这种软件缺陷可能会在软件运行的时候产生开发者意想不到的xx-not-found-bug,主要表现形式包括:java.lang.noclassdeffounderror、java.lang.classnotfoundexception、java.lang.nosuchmethoderror和java.lang.nosuchmethodexception。maven本身虽然可以检测依赖冲突,但缺乏有效的机制对依赖冲突进行评估。

java虚拟机中定义的class格式文件是编译java类文件后产生的字节码,每一个class文件都对应着唯一一个类或接口的定义信息,java类文件中的属性、方法,以及类中的常量信息,都会被存储在.class文件中。相对于易于程序员读写java文件,class文件的格式被更加严格的定义,更易于被程序分析。目前有asm、javassist等流行的工具可以在class形式的字节码文件进行操作,进行java类的产生、分析、修改。借助于soot等java优化框架可以分析java程序的内部结构,既能从单个java文件的角度分析每一条java语句,也可以从整个程序的角度分析每个java类,java方法之间的关系。

针对于maven环境中依赖冲突导致的not-found-bug问题,maven并未提供理想的解决方案。检测项目中的依赖冲突现象只能初步帮助开发者避免此类问题。结合程序内部的类和方法的关系对依赖冲突导致xx-not-found-bug的危险性进行评估比简单的侦测可以更进一步地帮助软件开发者避免程序运行时崩溃。



技术实现要素:

针对于项目中出现的依赖冲突,本发明通过静态分析得到程序运行可能需要加载执行的类和方法,并基于加载执行的可能性对maven环境中的依赖冲突导致的noclass和nomethod两种危险分别进行评估分级:使用类之间的引用关系评估noclass危险级别,使用方法之间的调用关系评估nomethod危险级别。

一种评估maven环境中依赖冲突危险级别的方法,包括流程如下,其中步骤3与步骤4不分先后顺序:

步骤1:获取到当前项目中使用的所有第三方依赖,包括直接依赖和间接依赖;

步骤2:对当前项目所有直接依赖和间接依赖进行遍历,识别当前项目中出现的所有依赖冲突;

步骤3:针对当前项目中的每个依赖冲突进行noclass危险级别的评估,包括步骤3.1~步骤3.6:

步骤3.1:识别出依赖冲突中用于编译当前项目的一个依赖usedjar,其余没有用于编译当前项目的多个依赖notusedjar构成集合notusedjarset,usedjar中的类构成集合usedjarclassset,notusedjar内部的类构成集合notusedjarclassset,如果有某个类存在于notusedjarclassset却不存在于usedjarclassset,则将该冲突noclass的危险级别设置为1;

步骤3.2:解析当前项目中所有被使用的jar包,得到当前项目和其第三方依赖中的类集合usedclassset;

步骤3.3:遍历当前noclass危险级别为1的依赖冲突,如果有某个类class存在于notusedjarclassset却不存在于usedclassset,则将该类添加到该依赖冲突的thrownclassset中,并将该冲突noclass的危险级别设置为2;

步骤3.4:根据类之间的classref关系,建立类关系的有向图classgraph,有向图中的节点为类,边的起点和终点为引用类和被引用的类,边的权值全部为1;

步骤3.5:解析当前项目,获取当前项目的宿主类集合hostclassset;

步骤3.6:遍历当前noclass危险级别为2的依赖冲突:基于classgraph,每次以依赖冲突的thrownclassset中的一个类为起点,使用dijkstra算法计算thrownclass到图中其他节点的最短路径距离,如果依赖冲突的thrownclassset中的某个类与hostclassset中的某个类的最短距离小于无穷大,则将该冲突noclass的危险级别设置为3;

所述最短路径距离计算方法流程包括步骤3.6.1~步骤3.6.5:

步骤3.6.1:初始时,从thrownclassset中选出一个未被计算的类v0,s={v0},t=v-s={项目中的其他类},t中顶点对应的距离值:若存在<v0,vi>的有向的类引用,d(v0,vi)为1,若不存在<v0,vi>的有向的类引用,d(v0,vi)为∞。

步骤3.6.2:从t中选取一个与s中节点有关联边且权值最小的顶点w,加入到s中。

步骤3.6.3:对其余t中节点的距离值进行修改:若加进w作中间节点,从v0到vi的距离值缩短,则修改此距离值。

步骤3.6.4:重复上述步骤3.6.2和3.6.3,直到s中包含所有顶点,即w=vi为止。

步骤3.6.5:重复上述步骤3.6.1~3.6.4,直到thrownclassset中的所有类到图中其他节点的最短距离都计算完毕。

步骤4:针对项目中的每个依赖冲突进行nomethod危险级别的评估,包括步骤4.1~步骤4.3:

步骤4.1:遍历每个依赖冲突,识别出冲突中用于编译当前项目的一个依赖usedjar,其余没有用于编译当前项目的多个依赖notusedjar构成集合notusedjarset,分析usedjar得到jar包中的类usedjarclassset,以及每个类包含的方法method,再分析每个notusedjar得到jar包中的类集合notusedjarclassset,以及每个类包含的方法method,如果存在某个方法method的类名既存在于usedjarclassset又存在于notusedjarclassset,但是只有notusedjar中的类对该方法有实现,则将该方法加入到对应notusedjar的thrownmethodset中,并将对应的依赖冲突nomethod的危险级别设置为1。

步骤4.2:遍历每个nomethod危险级别为1的依赖冲突,对于依赖冲突中的每个notusedjar的thrownmethodset中的元素thrownmethod,从thrownmethod的方法名methodname中提取类名classname,在usedjar中名为classname类为classa,如果classa的父类依然不存在对thrownmethod的实现,则将对应的依赖冲突nomethod的危险级别设置为2。

步骤4.3:遍历每个nomethod危险级别为2的依赖冲突,构建方法调用关系的有向图methodgraph。基于methodgraph,计算以项目为入口被执行的方法集合reachedmethodset。如果reachedmethodset中有thrownmethod则将对应的依赖冲突的危险级别设置为3。

步骤5:对评估结果进行封装,向开发者展现评估结果。

有益技术效果:

maven自身提供依赖冲突的检测机制,可以检测到当前项目中存在的所有依赖冲突。但并不是所有的依赖冲突都会导致bug的出现,如果为开发者报警所有的依赖冲突,则会产生大量的报警信息,而其中大量的假阳性报警则会导致开发者对于真正软件缺陷的忽视。本发明在maven的基础上为开发者提供更多关于依赖冲突的信息:不仅可以检测到项目中存在的依赖冲突,而且根据软件类和方法的内部联系对依赖冲突的危险等级进行了有效的评估。将依赖冲突进行分级可以帮助开发者更清晰地了解项目中存在的依赖冲突的危险性。软件开发者使用本发明优先处理高等级的依赖冲突,可以在有限的时间内最大程度的降低软件在运行时的出现xx-not-found-bug的风险。

附图说明

图1为本发明实施例的流程图;

图2为本发明实施例的评估noclass危险级别的流程图;

图3为本发明实施例的评估noclass危险级别的实例图;

图4为本发明实施例的评估nomethod危险级别的流程图;

图5为本发明实施例的评估nomethod危险级别的实例图。

具体实施方式

下面结合附图和具体实施实例对发明做进一步说明:

评估maven环境中依赖冲突危险级别的方法,包括如下流程,如图1所示:

步骤1:获取到当前项目中使用的所有第三方依赖,包括直接依赖和间接依赖:

在maven的构建环境中,写在pom文件中的依赖为直接依赖,写在直接依赖的pom里面的依赖为间接依赖,写在间接依赖pom文件中的依赖也称为间接依赖。以当前项目为根,所有的依赖构成树状结构,称为依赖树。使用maven的api接口,在dependencynodevisitor的子类中的visit方法编写相应逻辑,可以遍历依赖树上出现的每个依赖,包括直接依赖和间接依赖,并存储到程序中。

步骤2:对当前项目所有直接依赖和间接依赖进行遍历,识别当前项目中出现的所有依赖冲突:

maven的每个依赖使用groupid,artifact,version三个字段进行唯一标识,groupid表示依赖的开发机构,artifactid表示依赖的项目名称,version表示依赖的版本号。groupid和artifact相同则视为同一个第三方,如果正在开发的项目的依赖树中出现了同一个第三方的两个version则产生了依赖的冲突,当前项目在进行编译的时候只会使用其中的一个版本。为了识别出程序中存在的所有依赖冲突,需要统计程序引入的所有第三方,以及每个第三方被应用的版本,如果第三方被引用的版本超过1则构建一个冲突对象记录此冲突的相关数据。

步骤3:针对当前项目中的每个依赖冲突进行noclass危险级别的评估,包括步骤3.1~步骤3.6:如图2流程所示,图2中level1代表noclass的危险级别1,level2代表noclass的危险级别2,level3代表noclass的危险级别3。下面结合图3实例进行详述。图3中共存在三个冲突{(sample:risk1:1.0,sample:risk1:2.0),(sample:risk2:1.0,sample:risk2:2.0),(sample:risk3:1.0,sample:risk3:2.0)}.

步骤3.1:遍历每个依赖冲突,执行如下两个操作:

(1)在maven的整个依赖树上,树的节点为groupid:artifact:version唯一标识的依赖jar包,树的边表示上层节点依赖于下层节点。最后被maven使用的节点可以通过dependencynode的state判断,被使用的jar包的state为include。冲突中被使用的依赖为usedjar,其余没有被使用到的依赖构成集合notusedjarset,图3实例的识别结果如表格1所示:

表格1:图3实例的识别结果表

(2)使用soot工具可以在程序执行的时候将jar包进行解压,然后从解压后的后缀为.class的文件的文件名中提取出jar包中所有的类。对于每个冲突,使用soot解析usedjar得到usedjarclassset,解析notusedjarset中的notusedjar得到notusedjarclassset,如果差集notusedjarclassset-usedjarclassset中有元素,则将该冲突noclass的危险级别设置为1,noclass的危险级别评估结果表i如表格2所示:

表格2:noclass的危险级别评估结果表i

步骤3.2:使用soot解析依赖树上state为include的依赖,解析当前项目中所有被使用的jar包,得到当前项目和其第三方依赖中的类集合usedclassset。

图3实例中state为include的依赖jar包为sample:top:1.0,sample:middle:1.0,sample:risk1:2.0,sample:risk2:2.0,sample:risk3:2.0,所有jar包中的类构成usedclassset{class_top,class_middle,class_common1,class_common2,class_common3,class_risk1};

步骤3.3:遍历当前noclass危险级别为1的依赖冲突,如果notusedjarclassset-usedclassset中有元素,则将该类添加到该依赖冲突的thrownclassset中,并将该冲突noclass的危险级别设置为2,noclass的危险级别评估结果表ii如表格3所示:

表格3:noclass的危险级别评估结果表ii

步骤3.4:javassist可以通过对class文件进行分析,分析类文件中包含的信息得到类之间的引用关系。使用javassist解析出的类之间的classref关系,建立类关系的带权有向图classgraph,图中的节点为类,边的起点和终点为引用类和被引用的类,边的权值全部为1。

步骤3.5:当前项目的代码会被maven编译到对应工程文件夹的target目录下,使用soot解析target目录,获取当前项目的宿主类集合hostclassset。

步骤3.6:遍历当前noclass危险级别为2的依赖冲突:基于classgraph,每次以依赖冲突的thrownclassset中的一个类为起点,使用dijkstra算法计算thrownclass到图中其他节点的最短路径距离,如果冲突的thrownclassset中的某个类与hostclassset中的某个类的最短距离小于无穷大,则将该冲突noclass的危险级别设置为3;

步骤3.6.1:初始时,从thrownclassset中选出一个未被计算的类v0,s={v0},t=v-s={项目中的其他类},t中顶点对应的距离值:若存在<v0,vi>的有向的类引用,d(v0,vi)为1,若不存在<v0,vi>的有向的类引用,d(v0,vi)为∞。

步骤3.6.2:从t中选取一个与s中节点有关联边且权值最小的顶点w,加入到s中。

步骤3.6.3:对其余t中节点的距离值进行修改:若加进w作中间节点,从v0到vi的距离值缩短,则修改此距离值。

步骤3.6.4:重复上述步骤3.6.2和3.6.3,直到s中包含所有顶点,即w=vi为止。

步骤3.6.5:重复上述步骤3.6.1~3.6.4,直到thrownclassset中的所有类到图中其他节点的最短距离都计算完毕。

noclass的危险级别评估结果表iii如表格4所示:

表格4:noclass的危险级别评估结果表iii

步骤4:如图4所示,针对项目中的每个依赖冲突进行nomethod危险级别的评估,其中,图4中level1代表nomethod的危险级别1,level2代表nomethod的危险级别2,nomethod代表noclass的危险级别3。下面结合图5实例进行详述。

步骤4.1:遍历每个依赖冲突:识别出冲突中用于编译当前项目的依赖usedjar,其他没有用于编译当前项目的依赖notusedjar构成集合notusedjarset。使用java代码优化框架soot分析jar包中的class文件,得到jar包中的类以及类中的方法,图5实例的识别结果如表格5所示:

表格5:图5实例的识别结果

步骤4.1.1:对于每个冲突:使用soot分析usedjar,得到usedjar包中的类usedjarclassset,以及每个类包含的方法。

步骤4.1.2:对于每个冲突:遍历notusedjarset的每个notusedjar,使用soot解析notusedjar,得到jar包中的类notusedjarclassset,以及每个类包含的方法。取usedjarclassset和notusedjarclassset的交集得到commonclassset。如果commonclass的某个method只有notusedjar实现了,则将method加入thrownmethodset中,并将对应的依赖冲突nomethod的危险级别设置为1,nomethod的危险级别评估结果i如表格6所示:

表格6:nomethod的危险级别评估结果i

步骤4.2:遍历每个nomethod危险级别为1的依赖冲突,对于依赖冲突中的每个notusedjar的thrownmethodset中的元素thrownmethod:先使用soot得到thrownmethod的类thrownmethodclass,再使用soot得到其父类thrownmethodclassfather,如果父类中依然不存在对thrownmethod的实现,则将对应的依赖冲突nomethod的危险级别设置为2,nomethod的危险级别评估结果ii如表格7所示:

表格7:nomethod的危险级别评估结果ii

步骤4.3:基于方法调用关系,计算thrownmethod在实际运行时是否会被执行:

步骤4.3.1:遍历每个nomethod危险级别为2的依赖冲突,使用soot的全局模式构建系统的方法调用关系图的methodgraph。

步骤4.3.3:当前项目的代码会被maven编译到对应工程文件夹的target目录下,使用soot解析target目录,获取当前项目的方法集合hostmethodset。

步骤4.3.4:基于methodgraph,使用soot提供的接口计算以hostmethodset为入口可能会被执行的方法集合reachedmethodset。如果reachedmethodset中有thrownmethod则将对应的依赖冲突的nomethod的危险级别设置为3,nomethod的危险级别评估结果iii如表格8所示:

表格8:nomethod的危险级别评估结果iii:

步骤5:采用数据和展现形式分离的方式,将评估结果封装到数据结构中,对于同一个数据结构,用xml和html两种不同的展现逻辑,向开发者展现评估结果。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1