精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java方法完整調(diào)用鏈生成工具

開發(fā) 后端
本文實現(xiàn)了一個工具,能夠批量生成指定Java方法向下的完整調(diào)用鏈,對于關(guān)注的Java方法,能夠生成其向下調(diào)用的方法信息,及被調(diào)用方法再向下調(diào)用的方法,直到最下層被調(diào)用的方法。

1. 前言

在很多場景下,如果能夠生成Java代碼中方法之間的調(diào)用鏈,是很有幫助的,在代碼審計及漏洞分析等場景中也是。

IDEA提供了顯示調(diào)用指定Java方法向上的完整調(diào)用鏈的功能,可以通過“Navigate -> Call Hierarchy”菜單(快捷鍵:Ctrl+Alt+H)使用;Eclipse也提供了相同的功能。但以上都需要針對每個方法進行手工處理,拷貝出來的文本無法展示調(diào)用層級,且不支持生成指定Java方法向下的完整調(diào)用鏈。

以下實現(xiàn)了一個工具,能夠批量生成指定Java方法向下的完整調(diào)用鏈,對于關(guān)注的Java方法,能夠生成其向下調(diào)用的方法信息,及被調(diào)用方法再向下調(diào)用的方法,直到最下層被調(diào)用的方法。

也可以生成調(diào)用指定Java類向上的完整調(diào)用鏈,對于關(guān)注的Java類的方法,能夠生成調(diào)用對應(yīng)方法的方法信息,及調(diào)用上述方法的信息,直到最上層未被其他方法調(diào)用的方法(通常是對外提供的服務(wù),或定時任務(wù)等)。

2. 輸出結(jié)果示例

2.1. 調(diào)用指定類向上的完整調(diào)用鏈示例

調(diào)用指定類向上的完整調(diào)用鏈輸出結(jié)果格式類似一棵樹,每行代表一個Java方法,與實際的代碼執(zhí)行順序無關(guān),前面的數(shù)字越大代表調(diào)用層級越靠上,0代表指定類中的方法。

對于不被其他方法調(diào)用的方法,認為是入口方法,在對應(yīng)行的最后會顯示“!entry!”。

當(dāng)存在上述調(diào)用關(guān)系時,生成的調(diào)用指定類向上的完整調(diào)用鏈如下所示:

  1. [0]#DestClass.destfunc() 
  2. [1]#  ClassA3.funcA3() 
  3. [2]#    ClassA2.funcA2() 
  4. [3]#      ClassA1.funcA1()  !entry! 
  5. [1]#  ClassB1.funcB1()  !entry! 
  6. [1]#  ClassC2.funcC2() 
  7. [2]#    ClassC1.funcC1()    !entry! 

以下為使用該工具生成的調(diào)用Mybatis的SqlSessionUtils類的部分方法向上完整調(diào)用鏈(方法參數(shù)太長,已省略):

2.2. 指定方法向下完整調(diào)用鏈示例

指定方法向下完整調(diào)用鏈輸出結(jié)果類似一棵樹,每行代表一個Java方法,與實際的代碼執(zhí)行順序一致,前面的數(shù)字越大代表調(diào)用層級越靠下,0代表指定方法。

當(dāng)存在上述調(diào)用關(guān)系時,生成的指定方法向下完整調(diào)用鏈如下所示:

  1. [0]#DestClass.destfunc() 
  2. [1]#  ClassA1.funcA1() 
  3. [2]#    ClassA2a.funcA2a() 
  4. [2]#    ClassA2b.funcA2b() 
  5. [3]#      ClassA3.funcA3() 
  6. [1]#  ClassB1.funcB1() 
  7. [1]#  ClassC1.funcC1() 
  8. [2]#    ClassC2.funcC2() 

以下為使用該工具生成的Mybatis的SqlSessionFactoryBean:scanClasses()方法向下的完整調(diào)用鏈:

除此之外,當(dāng)方法指定了注解時,也可以顯示在結(jié)果中;當(dāng)出現(xiàn)方法循環(huán)調(diào)用時,會顯示出現(xiàn)循環(huán)調(diào)用的方法。

3. 適用場景

3.1. 分析代碼執(zhí)行流程

使用該工具生成指定方法向下調(diào)用鏈的功能,可以將代碼中復(fù)雜的方法調(diào)用轉(zhuǎn)換為相對簡單的方法調(diào)用鏈形式展示。

人工查看生成的調(diào)用鏈時,能夠通過類名及方法名識別出對應(yīng)含義。

支持將不關(guān)注的方法調(diào)用忽略,僅展示重要的方法調(diào)用。

對于分析代碼執(zhí)行流程有一定幫助,適合進行代碼審計時梳理交易流程、查找敏感API調(diào)用等場景。

3.2. 確認被修改代碼的影響范圍

使用該工具生成指定方法向上調(diào)用鏈的功能,可以生成調(diào)用指定類的所有方法的調(diào)用鏈。

能識別入口方法,減少人工逐層確認入口方法的工作量。

可用于快速確認被修改代碼的影響范圍。

3.3. 應(yīng)用功能拆分

在進行應(yīng)用功能拆分時,需要準確定位指定功能涉及的數(shù)據(jù)庫表,及使用了對應(yīng)數(shù)據(jù)庫表的相關(guān)入口方法。

使用該工具生成指定方法向下調(diào)用鏈的功能,生成指定入口方法向下的調(diào)用鏈,能夠根據(jù)類的包名快速找到Mapper接口(使用Mybatis的場景),即可找到相關(guān)的數(shù)據(jù)庫表。

使用該工具生成指定方法向上調(diào)用鏈的功能,生成調(diào)用指定Mapper接口向上的調(diào)用鏈,能夠根據(jù)“!entry!”找到入口方法。

重復(fù)執(zhí)行以上過程,直到?jīng)]有再找到新的Mapper接口(即數(shù)據(jù)庫表)和入口方法,即可確認指定功能涉及的數(shù)據(jù)庫表及相關(guān)入口方法。

4. 使用說明

4.1. 依賴環(huán)境

該工具將Java方法調(diào)用關(guān)系寫入文件之后,會將數(shù)據(jù)保存在數(shù)據(jù)庫中,需要訪問MySQL數(shù)據(jù)庫(理論上支持其他數(shù)據(jù)庫,但需要對SQL語句進行調(diào)整)。

所使用的數(shù)據(jù)庫用戶需要有DML讀寫權(quán)限,及DDL權(quán)限(需要執(zhí)行CREATE TABLE、TRUNCATE TABLE操作)。

4.2. 引入組件

在使用該工具前,首先需要在對應(yīng)的項目引入該工具組件的依賴,將其引入到test模塊或使用provided類型,可以避免發(fā)布到服務(wù)器中。

Gradle

  1. testImplementation 'com.github.adrninistrator:java-all-call-graph:0.0.8' 

Maven

  1. <dependency> 
  2.   <groupId>com.github.adrninistrator</groupId> 
  3.   <artifactId>java-all-call-graph</artifactId> 
  4.   <version>0.0.8</version> 
  5.   <type>provided</type> 
  6. </dependency> 

最新版本號可查看 https://search.maven.org/artifact/com.github.adrninistrator/java-all-call-graph 。

對應(yīng)代碼地址為 https://github.com/Adrninistrator/java-all-call-graph 。

建議在需要生成方法調(diào)用鏈的項目中分別引入依賴,可以使每個項目使用單獨的配置,不會相互影響。

該工具僅引入了log4j-over-slf4j組件,在引入該工具組件的項目中,還需要引入log4j2、logback等日志組件,且保證配置正確,能夠在本地正常運行。

4.3. 執(zhí)行步驟

4.3.1. 總體步驟

該工具的總體使用步驟如下:

a. 將后續(xù)步驟使用的幾個啟動類對應(yīng)的Java文件,及配置文件解壓到當(dāng)前Java項目的test模塊的對應(yīng)目錄中,該步驟只需要執(zhí)行一次;

b. 調(diào)用增強后的java-callgraph.jar(詳細內(nèi)容見后續(xù)“原理說明”部分),解析指定jar包中的class文件,將Java方法調(diào)用關(guān)系寫入文件;從該文件讀取Java方法調(diào)用關(guān)系,再寫入MySQL數(shù)據(jù)庫;

c.1 需要生成調(diào)用指定類的向上完整方法調(diào)用鏈時,從數(shù)據(jù)庫讀取方法調(diào)用關(guān)系,再將完整的方法調(diào)用鏈寫入文件;

c.2 需要生成指定方法的向下完整方法調(diào)用鏈時,從數(shù)據(jù)庫讀取方法調(diào)用關(guān)系,再將完整的方法調(diào)用鏈寫入文件;

如下圖所示:

4.3.2. 釋放啟動類及配置文件

當(dāng)前步驟在每個Java項目只需要執(zhí)行一次。

執(zhí)行當(dāng)前步驟時,需要執(zhí)行main()方法的類名如下:

  1. com.adrninistrator.jacg.unzip.UnzipFile 

需要選擇classpath對應(yīng)模塊為test。

執(zhí)行以上類后,會將java-all-callgraph.jar中保存配置文件的~jacg_config、~jacg_sql目錄,保存啟動類的“test/jacg”目錄,分別釋放到當(dāng)前Java項目的test模塊的resources、java目錄中(僅在本地生效,避免發(fā)布到服務(wù)器中)。

若當(dāng)前Java項目存在“src/test”或“src/unit.test”目錄,則將配置文件與Java文件分別釋放在該目錄的resources、java目錄中;

若當(dāng)前Java項目不存在以上目錄,則將上述文件釋放在“~jacg-[當(dāng)前時間戳]”目錄中,之后需要手工處理,將對應(yīng)目錄拷貝至test模塊對應(yīng)目錄中。

4.3.3. Java方法調(diào)用關(guān)系入庫

在生成Java方法調(diào)用關(guān)系并寫入數(shù)據(jù)庫之前,需要確保需要分析的jar包或war包已存在,對于通過源碼使用構(gòu)建工具生成的jar/war包,或者Maven倉庫中的jar包(需要是包含.class文件的jar包),均可支持。

當(dāng)需要解析的jar/war包中的class文件內(nèi)容發(fā)生變化時,需要重新執(zhí)行當(dāng)前步驟,以重新獲取對應(yīng)jar/war包中的Java方法調(diào)用關(guān)系,寫入文件及數(shù)據(jù)庫;若需要解析的jar/war包文件未發(fā)生變化,則不需要重新執(zhí)行當(dāng)前步驟。

執(zhí)行當(dāng)前步驟時,需要執(zhí)行main()方法的類名如下:

  1. test.jacg.TestRunnerWriteDb 

需要選擇classpath對應(yīng)模塊為test。

當(dāng)前步驟執(zhí)行的操作及使用的相關(guān)參數(shù)如下圖所示:

b.1 調(diào)用增強后的java-callgraph.jar中的類的方法

TestRunnerWriteDb類讀取配置文件 config.properties 中的參數(shù):

call.graph.jar.list :等待解析的jar包路徑列表,各jar包路徑之間使用空格分隔(若路徑中包含空格,則需要使用""包含對應(yīng)的路徑)

將第1個jar包路徑后面加上“.txt”作為本次保存Java方法調(diào)用關(guān)系文件路徑;

設(shè)置JVM參數(shù)“output.file”值為本次保存Java方法調(diào)用關(guān)系文件的路徑,調(diào)用增強后的java-callgraph.jar中的類的方法,通過方法的參數(shù)傳遞上述jar包路徑列表;

b.2 解析指定jar包

增強后的java-callgraph.jar中的類的方法開始解析指定的jar包;

b.3 將Java方法調(diào)用關(guān)系寫入文件

增強后的java-callgraph.jar中的類的方法將解析出的Java方法調(diào)用關(guān)系寫入指定的文件中;

b.4 讀取Java方法調(diào)用關(guān)系文件

TestRunnerWriteDb類讀取保存Java方法調(diào)用關(guān)系的文件,文件路徑即第1個jar包路徑加“.txt”;

b.5 將Java方法調(diào)用關(guān)系寫入數(shù)據(jù)庫

TestRunnerWriteDb類讀取配置文件 i_allowed_class_prefix.properties ,該文件中指定了需要處理的類名前綴,可指定包名,或包名+類名,示例如下:

  1. com.test 
  2. com.test.Test1 

讀取配置文件 config.properties 中的參數(shù):

app.name :當(dāng)前應(yīng)用名稱,對應(yīng)數(shù)據(jù)庫表名后綴,該參數(shù)值中的分隔符不能使用-,需要使用_

thread.num :寫入數(shù)據(jù)庫時并發(fā)處理的線程數(shù)量,也是數(shù)據(jù)源連接池數(shù)量

db.driver.name :數(shù)據(jù)庫驅(qū)動類名

db.url :數(shù)據(jù)庫URL,使用MySQL時,url需要指定rewriteBatchedStatements=true,開啟批量插入,提高效率

db.username :數(shù)據(jù)庫用戶名

db.password :數(shù)據(jù)庫密碼

input.ignore.other.package :忽略其他包的開關(guān),值為true/false;當(dāng)開關(guān)為開時,僅將 i_allowed_class_prefix.properties 中指定的類名前綴相符的類調(diào)用關(guān)系寫入數(shù)據(jù)庫;當(dāng)開關(guān)為關(guān)時,所有的類調(diào)用關(guān)系都寫入數(shù)據(jù)庫

向數(shù)據(jù)庫寫入數(shù)據(jù)庫前,會判斷對應(yīng)數(shù)據(jù)庫表是否存在,若不存在則創(chuàng)建,之后會執(zhí)行“TRUNCATE TABLE”操作清空表中的數(shù)據(jù);

根據(jù)配置文件 config.properties 中的 input.ignore.other.package 參數(shù)值及配置文件 i_allowed_class_prefix.properties ,將Java方法調(diào)用關(guān)系逐條寫入數(shù)據(jù)庫中;

增強后的java-callgraph.jar除了會將Java方法調(diào)用關(guān)系寫入文件外,還會將各個方法上的注解信息寫入文件(文件名為保存方法調(diào)用關(guān)系的文件名加上“-annotation.txt”);TestRunnerWriteDb類也會讀取對應(yīng)文件,將各方法上的注解信息寫入數(shù)據(jù)庫中。

4.3.4. 生成調(diào)用指定類向上的完整調(diào)用鏈

執(zhí)行當(dāng)前步驟之前,需要確認Java方法調(diào)用關(guān)系已成功寫入數(shù)據(jù)庫中。

執(zhí)行當(dāng)前步驟時,需要執(zhí)行main()方法的類名如下:

  1. test.jacg.TestRunnerGenAllGraph4Callee 

需要選擇classpath對應(yīng)模塊為test。

當(dāng)前步驟執(zhí)行的操作及使用的相關(guān)參數(shù)如下圖所示:

c.1.1 從數(shù)據(jù)庫讀取Java方法調(diào)用關(guān)系

TestRunnerGenAllGraph4Callee類讀取配置文件 o_g4callee_class_name.properties ,該文件中指定了需要生成向上完整調(diào)用鏈的類名;若存在同名類,則類名需要指定完整類名;若不存在同名類,則類名需要指定簡單類名;示例如下:

  1. Test1 
  2. com.test.Test1 

讀取配置文件 config.properties 中的參數(shù):

thread.num :從數(shù)據(jù)庫并發(fā)讀取數(shù)據(jù)的線程數(shù)量,也是數(shù)據(jù)源連接池數(shù)量;若 o_g4callee_class_name.properties 配置文件中的記錄數(shù)比該值小,則會使用記錄數(shù)覆蓋該參數(shù)值

以下參數(shù)說明略:app.name、db.driver.name、db.url、db.username、db.password

c.1.2 將方法完整調(diào)用鏈(向上)寫入文件

對于配置文件 o_g4callee_class_name.properties 中指定的類,對每個類生成一個對應(yīng)的文件,文件名為“[類名].txt”,在某個類對應(yīng)的文件中,會為對應(yīng)類的每個方法生成向上完整調(diào)用鏈;

以上文件名示例為“TestClass1.txt”;

每次執(zhí)行時會生成一個新的目錄,用于保存輸出文件,目錄名格式為“~jacg_output_for_callee/[yyyyMMdd-HHmmss.SSS]”;

讀取配置文件 config.properties 中的參數(shù):

call.graph.output.detail :輸出文件中調(diào)用關(guān)系的詳細程度,1: 最詳細,包含完整類名+方法名+方法參數(shù),2: 中等,包含完整類名+方法名,3: 最簡單,包含簡單類名(對于同名類展示完整類名)+方法名,示例如下

call.graph.output.detail參數(shù)值 顯示示例
1 com.test.Test1.func1(java.lang.String)
2 com.test.Test1.func1
3 Test1.func1

show.method.annotation :調(diào)用鏈中是否顯示方法上的注解開關(guān),值為true/false;當(dāng)開關(guān)為開時,會顯示當(dāng)前方法上的全部注解的完整類名,格式為“[方法信息]@注解1@注解2...”

gen.combined.output :是否生成調(diào)用鏈的合并文件開關(guān),值為true/false;當(dāng)開關(guān)為開時,在為各個類生成了對應(yīng)的調(diào)用鏈文件后,會生成一個將全部文件合并的文件,文件名為“~all-4callee.txt”

gen.upwards.methods.file :生成向上的調(diào)用鏈時,是否需要為每個方法生成單獨的文件開關(guān),值為true/false;當(dāng)開關(guān)為開時,會為o_g4callee_class_name.properties中指定的每個類的每個方法單獨生成一個文件,保存在“~jacg_output_for_callee/[yyyyMMdd-HHmmss.SSS]/methods”

4.3.5. 生成指定方法向下完整調(diào)用鏈

執(zhí)行當(dāng)前步驟之前,需要確認Java方法調(diào)用關(guān)系已成功寫入數(shù)據(jù)庫中。

4.3.5.1. 生成所有的調(diào)用鏈

執(zhí)行當(dāng)前步驟時,需要執(zhí)行main()方法的類名如下:

  1. test.jacg.TestRunnerGenAllGraph4Caller 

需要選擇classpath對應(yīng)模塊為test。

當(dāng)前步驟執(zhí)行的操作及使用的相關(guān)參數(shù)如下圖所示:

c.2.1 從數(shù)據(jù)庫讀取Java方法調(diào)用關(guān)系

TestRunnerGenAllGraph4Caller類讀取配置文件 o_g4caller_entry_method.properties ,該文件中指定了需要生成向下完整調(diào)用鏈的類名與方法名前綴,格式為[類名]:[方法名],或[類名]:[方法名]+參數(shù);

若存在同名類,則類名需要指定完整類名;若不存在同名類,則類名需要指定簡單類名;

示例如下:

  1. Test1:func1 
  2. Test1:func1( 
  3. Test1:func1(java.lang.String) 
  4. com.test.Test1:func1 
  5. com.test.Test1:func1( 
  6. com.test.Test1:func1(java.lang.String) 

若 o_g4caller_entry_method.properties 配置文件中指定的方法前綴對應(yīng)多個方法,則可在 o_g4caller_entry_method_ignore_prefix.properties 配置文件中指定需要忽略的方法前綴;

o_g4caller_entry_method_ignore_prefix.properties 配置文件的格式為方法名,或方法名+參數(shù),示例如下:

  1. func1 
  2. func1( 
  3. func1(java.lang.String) 

例如指定生成Class1.test方法的向下完整調(diào)用鏈,存在方法Class1.test1,則可指定忽略test1方法;指定生成Class1.test方法的向下完整調(diào)用鏈,所關(guān)注的test方法為test(java.lang.String),存在不關(guān)注的方法test(java.lang.Integer),則可指定忽略test(java.lang.Integer)方法;

讀取配置文件 config.properties 中的參數(shù):

thread.num :從數(shù)據(jù)庫并發(fā)讀取數(shù)據(jù)的線程數(shù)量,也是數(shù)據(jù)源連接池數(shù)量;若 o_g4caller_entry_method.properties 配置文件中的記錄數(shù)比該值小,則會使用記錄數(shù)覆蓋該參數(shù)值

以下參數(shù)說明略:app.name、db.driver.name、db.url、db.username、db.password

c.2.2 將方法完整調(diào)用鏈(向下)寫入文件

對于配置文件 o_g4caller_entry_method.properties 中指定的方法,對每個方法生成一個對應(yīng)的文件,文件名為“[類名]@[方法名]@[完整方法名HASH+長度].txt”;

以上文件名示例為“TestClass1@func1@qDb0chxHzmPj1F26S7kzhw#048.txt”;

每次執(zhí)行時會生成一個新的目錄,用于保存輸出文件,目錄名格式為“~jacg_output_for_caller/[yyyyMMdd-HHmmss.SSS]”;

讀取配置文件 config.properties 中的參數(shù):

gen.combined.output :是否生成調(diào)用鏈的合并文件開關(guān),值為true/false;當(dāng)開關(guān)為開時,在為各個類生成了對應(yīng)的調(diào)用鏈文件后,會生成一個將全部文件合并的文件,文件名為“~all-4caller.txt”

以下參數(shù)說明略:call.graph.output.detail、show.method.annotation。

4.3.5.2. 忽略特定的調(diào)用關(guān)系

以上生成指定方法向下的完整調(diào)用鏈中,包含了所有的方法調(diào)用鏈,可用于查找指定方法直接調(diào)用及間接調(diào)用的方法,例如通過調(diào)用的Mybatis的Mapper接口確認該方法相關(guān)的數(shù)據(jù)庫表操作;

當(dāng)生成指定方法向下的完整調(diào)用鏈是為了人工分析代碼結(jié)構(gòu)時,若包含了所有的方法調(diào)用鏈,則會有很多不重要的代碼產(chǎn)生干擾,例如對dto、entity等對象的讀取及賦值操作、通信數(shù)據(jù)序列化/反序列化操作(JSON等格式)、日期操作、流水號生成、請求字段格式檢查、注解/枚舉/常量/異常/日期相關(guān)類操作、Java對象默認方法調(diào)用等;

調(diào)用以下類,支持將不關(guān)注的方法調(diào)用關(guān)系忽略:

  1. test.jacg.TestRunnerGenAllGraph4CallerSupportIgnore 

在配置文件 o_g4caller_ignore_class_keyword.properties 中可以指定需要忽略的類名關(guān)鍵字,可為包名中的關(guān)鍵字,或類名中的關(guān)鍵字,示例如下:

  1. .dto. 
  2. .entity. 
  3. Enum 
  4. Constant 

在配置文件 o_g4caller_ignore_full_method_prefix.properties 中可以指定需要忽略的完整方法前綴,可指定包名,或包名+類名,或包名+類名+方法名,或包名+類名+方法名+參數(shù),示例如下:

  1. com.test 
  2. com.test.Test1 
  3. com.test.Test1:func1 
  4. com.test.Test1:func1( 
  5. com.test.Test1:func1(java.lang.String) 

在配置文件 o_g4caller_ignore_method_prefix.properties 中可以指定需要忽略的方法名前綴,如Java對象中的默認方法“toString()、hashCode()、equals(java.lang.Object)、<init>(、<clinit>(”等,示例如下:

  1. func1 
  2. func1(  
  3. func1() 
  4. func1(java.lang.String) 

5. 原理說明

5.1. Java方法調(diào)用關(guān)系獲取

在獲取Java方法調(diào)用關(guān)系時,使用了 https://github.com/gousiosg/java-callgraph 項目,并對其進行了增強,java-callgraph使用Apache Commons BCEL(Byte Code Engineering Library)解析Java方法調(diào)用關(guān)系,Matthieu Vergne( https://www.matthieu-vergne.fr/ )為該項目增加了解析動態(tài)調(diào)用的能力(lambda表達式等)。

原始java-callgraph在多數(shù)場景下能夠獲取到Java方法調(diào)用關(guān)系,但以下場景的調(diào)用關(guān)系會缺失:

接口與實現(xiàn)類方法

假如存在接口Interface1,及其實現(xiàn)類Impl1,若在某個類Class1中引入了接口Interface1,實際為實現(xiàn)類Impl1的實例(使用Spring時的常見場景),在其方法Class1.func1()中調(diào)用了Interface1.fi()方法;

原始java-callgraph生成的方法調(diào)用關(guān)系中,只包含Class1.func1()調(diào)用Interface1.fi()的關(guān)系,Class1.func1()調(diào)用Impl1.fi(),及Impl1.fi()向下調(diào)用的關(guān)系會缺失。

Runnable實現(xiàn)類線程調(diào)用

假如f1()方法中使用內(nèi)部匿名類形式的Runnable實現(xiàn)類在線程中執(zhí)行操作,在線程中執(zhí)行了f2()方法,如下所示:

  1. private void f1() { 
  2.     new Thread(new Runnable() { 
  3.         @Override 
  4.         public void run() { 
  5.             f2(); 
  6.         } 
  7.     }).start(); 

原始java-callgraph生成的方法調(diào)用關(guān)系中,f1()調(diào)用f2(),及f2()向下調(diào)用的關(guān)系會缺失;

對于使用命名類形式的Runnable實現(xiàn)類在線程中執(zhí)行操作的情況,存在相同的問題,原方法調(diào)用線程中執(zhí)行的方法,及繼續(xù)向下的調(diào)用關(guān)系會缺失。

Thread子類線程調(diào)用

與Runnable實現(xiàn)類線程調(diào)用情況類似,略。

lambda表達式(含線程調(diào)用等)

假如f1()方法中使用lambda表達式的形式在線程中執(zhí)行操作,在線程中執(zhí)行了f2()方法,如下所示:

  1. private void f1() { 
  2.     new Thread(() -> f2()).start(); 

原始java-callgraph生成的方法調(diào)用關(guān)系中,f1()調(diào)用f2(),及f2()向下調(diào)用的關(guān)系會缺失;

對于其他使用lambda表達式的情況,存在相同的問題,原方法調(diào)用lambda表達式中執(zhí)行的方法,及繼續(xù)向下的調(diào)用關(guān)系會缺失。

父類調(diào)用子類的實現(xiàn)方法

假如存在抽象父類Abstract1,及其非抽象子類ChildImpl1,若在某個類Class1中引入了抽象父類Abstract1,實際為子類ChildImpl1的實例(使用Spring時的常見場景),在其方法Class1.func1()中調(diào)用了Abstract1.fa()方法;

原始java-callgraph生成的方法調(diào)用關(guān)系中,只包含Class1.func1()調(diào)用Abstract1.fa()的關(guān)系,Class1.func1()調(diào)用ChildImpl1.fa()的關(guān)系會缺失。

子類調(diào)用父類的實現(xiàn)方法

假如存在抽象父類Abstract1,及其非抽象子類ChildImpl1,若在ChildImpl1.fc1()方法中調(diào)用了父類Abstract1實現(xiàn)的方法fi();

原始java-callgraph生成的方法調(diào)用關(guān)系中,ChildImpl1.fc1()調(diào)用Abstract1.fi()的關(guān)系會缺失。

針對以上問題,增強后的java-callgraph都進行了優(yōu)化,能夠生成缺失的調(diào)用關(guān)系。

增強后的java-callgraph地址為 https://github.com/Adrninistrator/java-callgraph 。

對于更復(fù)雜的情況,例如存在接口Interface1,及其抽象實現(xiàn)類Abstract1,及其子類ChildImpl1,若在某個類中引入了抽象實現(xiàn)類Abstract1并調(diào)用其方法的情況,生成的方法調(diào)用關(guān)系中也不會出現(xiàn)缺失。

5.2. Java方法完整調(diào)用鏈生成

在獲取了Java方法調(diào)用關(guān)系之后,將其保存在數(shù)據(jù)庫中,涉及到3個數(shù)據(jù)庫表,可查看java-all-callgraph.jar釋放的~jacg_sql目錄中的.sql文件,相關(guān)數(shù)據(jù)庫表如下所示:

表名前綴 注釋 作用
class_name_ 類名信息表 保存相關(guān)類的完整類名及簡單類名
method_annotation_ 方法注解表 保存方法及方法上的注解信息
method_call_ 方法調(diào)用關(guān)系表 保存各方法之間調(diào)用信息

上述數(shù)據(jù)庫表在創(chuàng)建時使用表名前綴加上配置文件 config.properties 中的 app.name 參數(shù)值。

該工具會主要從方法調(diào)用關(guān)系表中逐級查詢數(shù)據(jù),生成完整的方法調(diào)用鏈。

6. 其他功能

6.1. 處理循環(huán)方法調(diào)用

在生成向上或向下的Java方法完整調(diào)用鏈時,若出現(xiàn)了循環(huán)方法調(diào)用,該工具會從循環(huán)調(diào)用中跳出,并在生成的方法調(diào)用鏈中對出現(xiàn)循環(huán)調(diào)用的方法增加標(biāo)記“!cycle[n]!”,其中n代表被循環(huán)調(diào)用的方法對應(yīng)層級。

生成向上的Java方法完整調(diào)用鏈時,出現(xiàn)循環(huán)方法調(diào)用的示例如下:

  1. [0]#org.springframework.transaction.TransactionDefinition:getIsolationLevel 
  2. [1]#  org.springframework.transaction.support.DelegatingTransactionDefinition:getIsolationLevel 
  3. [2]#    org.springframework.transaction.TransactionDefinition:getIsolationLevel !cycle[0]! 

生成向下的Java方法完整調(diào)用鏈時,出現(xiàn)循環(huán)方法調(diào)用的示例如下:

  1. [0]#org.springframework.transaction.support.TransactionTemplate:execute 
  2. [1]#  org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager:execute 
  3. [2]#    org.springframework.transaction.jta.WebSphereUowTransactionManager:execute 
  4. [3]#      org.springframework.transaction.TransactionDefinition:getTimeout 
  5. [4]#        org.springframework.transaction.support.DefaultTransactionDefinition:getTimeout 
  6. [4]#        org.springframework.transaction.support.DelegatingTransactionDefinition:getTimeout 
  7. [5]#          org.springframework.transaction.TransactionDefinition:getTimeout  !cycle[3]! 

6.2. 生成兩個方法之間的調(diào)用鏈

該工具生成的向上或向下的Java方法完整調(diào)用鏈通常會比較大,如果只關(guān)注某個方法到起始方法之間的調(diào)用鏈時,可以按照以下步驟生成:

執(zhí)行以下java類:

  1. com.adrninistrator.jacg.other.GenSingleCallGraph 

需要選擇classpath對應(yīng)模塊為test。

在程序參數(shù)(即main()方法處理的參數(shù))中指定對應(yīng)的向上或向下的Java方法完整調(diào)用鏈文件路徑,及關(guān)注的方法所在行數(shù),格式為“[完整調(diào)用鏈文件路徑] [關(guān)注方法所在行數(shù)]”。

當(dāng)文件路徑包含空格時,需要使用""包含;關(guān)注方法所在行數(shù)從1開始。

例如完整調(diào)用鏈文件“dir/a.txt”內(nèi)容如下:

  1. [0]#DestClass.destfunc() 
  2. [1]#  ClassA3.funcA3() 
  3. [2]#    ClassA2.funcA2() 
  4. [3]#      ClassA1.funcA1()  !entry! 
  5. [1]#  ClassB1.funcB1()  !entry! 
  6. [1]#  ClassC2.funcC2() 
  7. [2]#    ClassC1.funcC1()    !entry! 

假如希望知道第7行“[2]# ClassC1.funcC1() !entry!”方法與起始方法“[0]#DestClass.destfunc()”之間的調(diào)用關(guān)系,可在執(zhí)行以上類時指定程序參數(shù)為“dir/a.txt 7”,則生成調(diào)用關(guān)系如下:

  1. [0]#DestClass.destfunc() 
  2. [1]#  ClassC2.funcC2() 
  3. [2]#    ClassC1.funcC1()    !entry! 

7. 分析腳本

在 https://github.com/Adrninistrator/java-all-call-graph 的“shell腳本”、“SQL語句”目錄中,保存了以下腳本,可以用于對代碼進行一些分析操作。

7.1. shell腳本

根據(jù)Mybatis的Mapper查找對應(yīng)數(shù)據(jù)庫表名

根據(jù)數(shù)據(jù)庫表名查找Mybatis的對應(yīng)Mapper

根據(jù)向上完整調(diào)用鏈查找入口方法完整類名

根據(jù)向上完整調(diào)用鏈查找入口方法簡單類名

根據(jù)向下完整調(diào)用鏈查找被使用的Mapper完整類名

根據(jù)向下完整調(diào)用鏈查找被使用的Mapper方法

根據(jù)向下完整調(diào)用鏈查找被使用的Mapper簡單類名

7.2. SQL語句

針對該工具使用的數(shù)據(jù)庫表進行分析的SQL語句。

8. 無法正確處理的情況

以下情況,對應(yīng)的方法找不到被調(diào)用關(guān)系,可能會被誤識別為入口方法:

不是直接通過Java方法進行調(diào)用的情況(例如在XML文件中配置代碼執(zhí)行流程、通過注解配置代碼執(zhí)行流程、使用AOP處理等);

未被調(diào)用的方法;

方法作為流式處理的參數(shù),如“xxx.stream().filter(this::func)”。

9. 使用建議

可能存在以下問題:

當(dāng)一個接口對應(yīng)多個實現(xiàn)類時,若在某個類中引入了接口,并調(diào)用其方法,生成的完整調(diào)用鏈中,可能將當(dāng)前類未使用的其他實現(xiàn)類相關(guān)的調(diào)用關(guān)系也包含進來;

當(dāng)一個抽象父類對應(yīng)多個非抽象子類時,若在某個類中引入了抽象父類,并調(diào)用其方法,生成的完整調(diào)用鏈中,可能將當(dāng)前類未使用的其他非抽象子類相關(guān)的調(diào)用關(guān)系也包含進來。

對于以上問題,可以臨時修改代碼但不提交,將引入的接口使用實現(xiàn)類替代,或抽象父類使用非抽象子類替代,生成jar包/war包后生成調(diào)用關(guān)系,再重新生成完整調(diào)用鏈。

 

責(zé)任編輯:張燕妮 來源: FreeBuf
相關(guān)推薦

2021-05-25 09:59:50

前端開發(fā)工具

2021-04-23 23:27:00

數(shù)據(jù)資產(chǎn)IT運營

2022-08-15 08:02:09

Go程序函數(shù)

2012-02-07 13:21:37

Java

2023-08-11 08:02:36

Gogonew工具鏈

2014-03-18 14:30:51

游戲引擎cocos2d-x

2021-03-06 08:05:54

工具DevOpsLighthouse

2020-08-21 07:00:00

DevOpsIT開發(fā)

2023-11-29 09:00:00

KubernetesDevOps

2021-01-29 15:50:45

DevOps運維

2021-03-14 22:34:05

工具RMS應(yīng)用層

2019-12-12 09:30:31

工具代碼開發(fā)

2022-02-15 17:56:19

SpringBoot日志

2015-08-28 09:38:51

Linux源代碼分析工具

2017-03-10 14:54:42

京東智慧供應(yīng)鏈

2017-09-07 19:21:20

Java語言Iodine

2012-03-01 13:34:02

Java

2011-08-29 09:54:45

LUAJAVA 方法

2009-12-08 17:15:43

PHP調(diào)用Java語言
點贊
收藏

51CTO技術(shù)棧公眾號

色999日韩| 老色鬼在线视频| 精彩视频一区二区| 欧美激情欧美激情| 久久久久久久久免费看无码 | 任你操这里只有精品| 色开心亚洲综合| 成人精品视频一区二区三区| 欧洲精品久久久| 天天天天天天天天操| 天堂网av成人| 日韩欧美国产麻豆| 狠狠躁狠狠躁视频专区| 精精国产xxxx视频在线野外 | 在线视频不卡一区二区| 可以免费观看的毛片| 日韩精品亚洲专区| 久久久久久有精品国产| 青青青视频在线播放| 成午夜精品一区二区三区软件| 91久久国产最好的精华液| 白白操在线视频| 成人在线观看网站| 成人高清视频在线观看| 成人亚洲欧美一区二区三区| 二区视频在线观看| 国产一区二区三区自拍| 深夜福利一区二区| 免费看污片网站| 狼人天天伊人久久| 日韩一级完整毛片| 蜜臀一区二区三区精品免费视频 | 欧美日韩亚洲激情| 欧美人与动牲交xxxxbbbb| 欧美在线观看在线观看| 成人自拍视频在线| 99久久一区三区四区免费| 在线免费观看一级片| 老牛嫩草一区二区三区日本 | 成人午夜激情视频| 亚洲一区二区三区乱码aⅴ蜜桃女 亚洲一区二区三区乱码aⅴ | 艹b视频在线观看| 偷拍精品精品一区二区三区| 精品福利在线观看| 黄页免费在线观看视频| 久久不射影院| 亚洲国产另类精品专区| 国产日本在线播放| 高端美女服务在线视频播放| 一二三四区精品视频| 欧美性视频在线播放| 三区四区电影在线观看| 国产精品嫩草99a| 一区二区三区欧美在线| √天堂资源地址在线官网| 亚洲国产精品国自产拍av| 欧洲精品一区色| 欧美精品a∨在线观看不卡| 久久免费午夜影院| 日本一区二区三区免费看| 第一页在线观看| 日本一区二区高清| 波多野结衣三级在线| caopeng在线| 亚洲亚洲精品在线观看| 欧美 日韩 国产在线观看| 天堂资源在线| 欧美优质美女网站| 日日干日日操日日射| 欧美日韩国产一区二区在线观看| 欧美一区二区三区免费大片| 亚洲成a人片在线www| 精品av导航| 亚洲精品中文字幕av| 国产精品av久久久久久无| 日韩专区精品| 欧美精品免费在线| 日韩三级视频在线播放| 天堂蜜桃91精品| 成人h视频在线观看播放| 性色av蜜臀av| 99国内精品久久| 日韩精品久久久| 国产丝袜在线| 天天综合网 天天综合色| 网站一区二区三区| 日本一区二区三区播放| 精品爽片免费看久久| 麻豆一区在线观看| 伊人成人在线视频| 国产精品成人一区二区| 国产偷拍一区二区| 99免费精品视频| 亚洲视频电影| 国产直播在线| 欧美剧情片在线观看| 人妻体内射精一区二区三区| 激情婷婷综合| 欧美黑人巨大精品一区二区| 久久久久久久久久一级| 国产精品一区二区视频| 欧美日韩亚洲免费| 欧美xxxx做受欧美88bbw| 日本高清视频一区二区| 女女调教被c哭捆绑喷水百合| 亚洲aa在线| 久99九色视频在线观看| 国产一级精品毛片| 污污网站免费看| 免费成人网www| 欧美激情一级二级| 自拍偷拍福利视频| 久久婷婷国产综合国色天香| 三级在线免费观看| 农村妇女一区二区| 亚洲欧美一区二区精品久久久| 激情视频在线播放| 久久99久久精品欧美| 欧美中日韩一区二区三区| 国产一线二线在线观看| 制服丝袜成人动漫| 国产精品18在线| 手机精品视频在线观看| 精品亚洲欧美日韩| 丁香花高清在线观看完整版| 日韩视频永久免费| 手机在线免费看片| 韩国一区二区视频| 一区二区不卡视频| www.26天天久久天堂| 亚洲欧美制服综合另类| 中日韩黄色大片| 成人国产免费视频| 欧美亚洲日本一区二区三区 | 六十路精品视频| 美女尤物在线视频| 欧美成人一区二区三区片免费| 萌白酱视频在线| 日韩和欧美一区二区| 欧美日韩喷水| 二区三区不卡| 亚洲精品在线视频| 亚洲第一网站在线观看| 久久久青草青青国产亚洲免观| 国产h视频在线播放| 国产精品毛片视频| 国内精品久久久久久影视8| 高清乱码毛片入口| 亚洲成人午夜影院| 久久人妻少妇嫩草av无码专区| 亚洲清纯自拍| 欧美成人第一区| www.日韩| 中文字幕国内精品| 91精品国产乱码久久| 国产精品家庭影院| 手机免费看av网站| 欧美+日本+国产+在线a∨观看| 97久久人人超碰caoprom欧美| 丝袜在线视频| 日韩电影中文字幕av| 欧美黑人一区二区| 亚洲国产精品成人久久综合一区 | 国产成人精品影视| 中文字幕无码精品亚洲资源网久久| 国产欧美三级电影| 欧亚精品在线观看| 91社区在线| 精品人伦一区二区色婷婷| 日韩久久久久久久久| 久久久久久**毛片大全| 日日躁夜夜躁aaaabbbb| 欧美 日韩 国产 一区| 国产在线欧美日韩| yiren22亚洲综合| 欧美大片va欧美在线播放| 色欲av伊人久久大香线蕉影院| 欧美性高潮床叫视频| 69精品无码成人久久久久久| 国产揄拍国内精品对白| 免费国产a级片| 日本道不卡免费一区| 91超碰rencao97精品| 手机在线观看av| 北条麻妃一区二区三区中文字幕| 免费看国产片在线观看| 欧美羞羞免费网站| 国产真实的和子乱拍在线观看| 久久久久久久电影| 亚洲区 欧美区| 久久精品日韩欧美| 日本一道在线观看| 国产不卡av一区二区| 亚洲mm色国产网站| 久久久久久久| 蜜臀av在线| 精品国产露脸精彩对白 | 欧美日韩一区小说| 国产一级中文字幕| 国产精品久久久久国产精品日日| 国产精久久久久| 免费观看30秒视频久久| 亚洲 欧美 日韩 国产综合 在线| 91麻豆国产自产在线观看亚洲| 国产传媒欧美日韩| 国产精品一区二区精品视频观看| 7777精品久久久久久| 蜜桃视频网站在线观看| 亚洲欧美资源在线| 丰满少妇一级片| 欧美片网站yy| 国产真人无遮挡作爱免费视频| 一区二区三区欧美| www.涩涩爱| 91麻豆国产福利在线观看| 一级全黄裸体片| 美女精品一区二区| 粗暴91大变态调教| 99热在线精品观看| www.国产在线播放| 欧美一区二区三区免费看| 深田咏美在线x99av| 好吊妞视频这里有精品| 亚洲一区二区免费| 小说区图片区亚洲| 国产精品久久久久久av下载红粉| 丁香花在线影院| 欧美精品videos| 综合久久2019| 麻豆国产va免费精品高清在线| 国产福利小视频在线观看| 精品亚洲精品福利线在观看| 亚洲精品无码专区| 日韩欧美的一区二区| 国产精品一二三四五区| 欧美日韩在线不卡| 成人黄色三级视频| 在线观看不卡一区| 无码人妻精品一区二区三区9厂| 午夜av电影一区| 日韩xxx高潮hd| 偷窥国产亚洲免费视频| 日本a在线观看| 黄色91在线观看| 日韩污视频在线观看| 精品久久久久久久久久久| 国产精品日日夜夜| 婷婷成人综合网| 亚洲自拍一区在线观看| 色哟哟精品一区| 亚洲天堂五月天| 欧美日韩一区二区在线视频| 一区两区小视频| 91精品国产综合久久久久久久 | 日韩一级在线视频| 91九色最新地址| 一级做a爱片性色毛片| 欧美美女一区二区| 国产成人毛毛毛片| 亚洲精品mp4| 国产人成在线观看| www.欧美免费| 日本一级理论片在线大全| 久久久久久亚洲| 日韩成人动漫| 国产精品午夜视频| 四虎国产精品永久在线国在线| 成人黄色在线播放| av不卡一区二区| 久久综合九九| 成人中文在线| 欧美日韩激情四射| 一本久道综合久久精品| 另类小说第一页| 国产黄色91视频| 日韩片在线观看| 国产精品久久夜| 久久影院一区二区| 欧美视频在线免费看| 91在线你懂的| 日韩av在线免费观看| 在线日本视频| 97久久精品国产| 久久精品黄色| 国产精品二区三区| 精品一二三区| www.亚洲成人网| 日韩高清中文字幕一区| 日本黄色大片在线观看| 国产日产欧产精品推荐色| 亚洲国产美女视频| 色综合视频在线观看| 国产美女永久免费| 亚洲免费av网址| gogo在线高清视频| 国产精品成人国产乱一区| 91成人午夜| 一区二区三区三区在线| 亚洲综合日本| 美女网站视频在线观看| 国产精品国产三级国产专播品爱网| 国产亚洲精品女人久久久久久| 欧美亚洲一区二区在线| 蜜桃av噜噜一区二区三区麻豆| 宅男66日本亚洲欧美视频| wwwww亚洲| 91成人在线看| 久久一区二区三区喷水| 亚洲熟妇国产熟妇肥婆| 国产老妇另类xxxxx| 91麻豆精品国产91久久综合| 五月婷婷激情综合| av网站免费大全| 色婷婷成人综合| 桃花岛tv亚洲品质| 久久天天狠狠| 国产综合网站| aaaaaaaa毛片| 国产精品国产a级| 黄色av一区二区| 亚洲欧美日韩综合| 中文字幕在线视频网站| 国产欧美欧洲| 激情视频一区| 亚洲欧美日韩中文字幕在线观看| 国产精品欧美精品| 午夜精品久久久久久久蜜桃| 亚洲乱码av中文一区二区| 2001个疯子在线观看| 99久久99| 欧美91精品| 久久精品一二三四| 亚洲激情第一区| av男人天堂网| 欧美巨大黑人极品精男| 国产精品亚洲欧美一级在线 | 人人澡人人添人人爽一区二区| 成人福利在线观看| 欧美激情欧美| 91视频福利网| 亚洲综合免费观看高清完整版| 99久久精品无免国产免费| 久青草国产97香蕉在线视频| 不卡精品视频| 免费在线黄网站| 波多野结衣中文一区| 国产污片在线观看| 日韩麻豆第一页| 久久电影tv| 亚洲日本精品| 激情图区综合网| 五月天丁香激情| 亚洲成在人线av| 亚洲精品**中文毛片| 欧美一区视久久| 裸体在线国模精品偷拍| xxxx日本少妇| 亚洲成人av片| 成人勉费视频| 色播亚洲婷婷| 国产精品亚洲午夜一区二区三区| 久久久久久久国产精品毛片| 亚洲第一级黄色片| 免费观看亚洲| 亚洲欧洲另类精品久久综合| 国内精品自线一区二区三区视频| 久久久精品人妻一区二区三区四 | 久久精品三级视频| 在线成人免费视频| 黄色成人在线网| 日本不卡免费新一二三区| 狠狠色伊人亚洲综合成人| 欧美成人综合色| 亚洲美女av黄| 91麻豆精品| 乱妇乱女熟妇熟女网站| 国产精品视频一二| 国产高清在线免费| 日本成人黄色片| 一级欧洲+日本+国产| 91av在线免费| 欧美日免费三级在线| h片视频在线观看| 亚洲黄色成人久久久| 成人免费毛片片v| 成人黄色激情视频| 久久久久久国产免费 | 人妻激情另类乱人伦人妻| 91亚洲永久精品| 国产精品一级视频| 57pao成人永久免费视频| 久久精品国产大片免费观看| 在线xxxxx| 这里只有精品视频在线观看| 色综合桃花网| 黄色片免费在线观看视频| 国产欧美一区二区精品忘忧草 | av免费看网址| 中文字幕在线观看不卡| 免费观看成年在线视频网站|