精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

欧美日一区二区三区在线观看国产免| 黄色在线免费看| 亚洲影院免费| 最近2019年日本中文免费字幕| 久久久精品麻豆| 18视频在线观看| 久久久久久久综合狠狠综合| 国产精品入口尤物| 黄色小视频在线免费看| 精品freesex老太交| 日韩一区二区电影| 国产精品wwwww| www.久久久久.com| 久久久精品免费网站| 91中文字精品一区二区| 成人av网站在线播放| 欧美日韩国产高清| 夜夜嗨av色一区二区不卡| 久久久久亚洲av无码网站| 欧美xoxoxo| 亚洲图片一区二区| 日本精品免费| 午夜av免费在线观看| 激情五月激情综合网| 欧美一级淫片播放口| 精品国产乱码久久久久久鸭王1| 亚洲色图丝袜| 精品91自产拍在线观看一区| 久久撸在线视频| 9i看片成人免费高清| 亚洲尤物视频在线| 伊人婷婷久久| 国产黄在线看| 91色乱码一区二区三区| 国产91一区二区三区| 青娱乐在线免费视频| 亚洲理伦在线| 欧美黄色片免费观看| 少妇视频一区二区| 精品视频国产| 国产香蕉一区二区三区在线视频 | 亚洲天堂手机| 一区二区三区在线观看欧美 | 国内一区二区三区| 久久精品国产91精品亚洲| 香蕉视频久久久| 一呦二呦三呦国产精品| 日韩av有码在线| 国产一级二级视频| 国产+成+人+亚洲欧洲在线| 日韩欧美在线一区二区三区| 亚洲午夜激情影院| 亚洲欧美综合久久久久久v动漫| 欧美午夜精品免费| www午夜视频| 久久亚洲精品中文字幕| 欧美午夜宅男影院| 91香蕉视频导航| 欧美国产日韩电影| 欧美偷拍一区二区| a在线观看免费视频| 成人国产精品| 欧美精品视频www在线观看| 国产精品v日韩精品v在线观看| 影视一区二区三区| 色999日韩国产欧美一区二区| 日韩av三级在线| 午夜影视一区二区三区| 欧美性xxxx| 青青草精品视频在线观看| 粉嫩av一区二区三区四区五区| 欧美亚洲丝袜传媒另类| 国产色视频在线播放| 99热这里有精品| 精品国产乱码久久久久久图片| 亚洲天堂2024| 香蕉一区二区| 中文字幕日韩欧美在线 | 日漫免费在线观看网站| 97精品视频在线观看自产线路二| 蜜桃网站成人| 日韩av中文| 亚洲一区二区三区中文字幕在线 | 制服丝袜av在线| 精品国产一区二区三区成人影院 | 久久都是精品| 国产精选久久久久久| 国产浮力第一页| av电影一区二区| 色噜噜一区二区| 亚洲小说区图片| 日韩欧美a级成人黄色| 国产精品igao| 视频一区日韩精品| 国产偷亚洲偷欧美偷精品| 九九九视频在线观看| 亚洲欧美在线专区| 欧美中文字幕视频| 国产精品无码久久av| www.视频一区| 亚洲一卡二卡三卡| 不卡视频观看| 欧美精品在线观看播放| 熟女人妻在线视频| 1024精品久久久久久久久| 2021国产精品视频| 国产精品九九九九| 久久综合狠狠综合久久综合88| 亚洲最大色综合成人av| 丁香花电影在线观看完整版| 在线观看亚洲精品| 国产婷婷在线观看| 午夜激情久久| 欧美亚洲日本网站| 精品人妻aV中文字幕乱码色欲| 久久嫩草精品久久久精品| 综合网五月天| 亚洲www啪成人一区二区| 日韩三级在线观看| 日本裸体美女视频| 男女精品网站| 国产精品久久九九| 麻豆最新免费在线视频| 日本韩国精品在线| 无码一区二区精品| 国产真实久久| 亚洲自拍另类欧美丝袜| 日韩理伦片在线| 欧美影院一区二区三区| 成人亚洲激情网| 在线观看你懂的视频| av一区二区在线观看| 77777少妇光屁股久久一区| 国产成人麻豆精品午夜在线| 国产精品黄色在线观看| 日韩欧美黄色大片| 免费成人av| 欧美一级视频免费在线观看| 熟妇高潮一区二区三区| 夜夜嗨av一区二区三区四季av| 亚洲精品www.| 久久五月天小说| 国产自摸综合网| 亚洲1卡2卡3卡4卡乱码精品| 在线观看亚洲专区| 日本爱爱爱视频| 日日夜夜一区二区| 日韩视频在线播放| 日韩欧美精品一区二区综合视频| 亚洲天堂男人天堂| 日本久久综合网| 久久精品欧美一区二区三区不卡 | 亚洲精品一区二区在线观看| www.毛片com| 国产精品一二三区在线| 国内自拍中文字幕| jazzjazz国产精品久久| 久久久久久国产免费| 国模人体一区二区| 激情成人中文字幕| 无遮挡aaaaa大片免费看| 久久aⅴ乱码一区二区三区| 久久亚洲高清| av有声小说一区二区三区| 一本色道久久88综合日韩精品 | 奇米影视一区二区三区| 日韩欧美国产二区| 国产日本久久| 九九综合九九综合| 黑人操亚洲女人| 精品久久久久久国产91| 欧美多人猛交狂配| 六月婷婷色综合| 久久精品在线免费视频| 超碰成人在线观看| 欧美一级高清免费| 91在线视频| 日韩欧美自拍偷拍| 久久免费激情视频| 国产精品色哟哟网站| 91插插插影院| 日韩午夜免费| 日韩hmxxxx| 日韩区欧美区| 奇米4444一区二区三区| 国产激情在线| 亚洲精品成a人在线观看| 国产精品自拍第一页| 亚洲日本丝袜连裤袜办公室| 大乳护士喂奶hd| 日韩二区三区在线观看| 亚洲天堂第一区| 日韩精品免费一区二区夜夜嗨| 国产精品美女久久久久久免费| 欧美成人视屏| 精品网站999www| 国产婷婷在线视频| 欧美性猛交xxxx免费看| 免费在线观看a级片| www.久久精品| 天天干天天色天天干| 国产精品主播| 久久久天堂国产精品| 久久爱www成人| 91福利入口| 日韩欧美一区二区三区免费观看 | 久久久久久久9999| 国产亚洲欧美一级| 亚洲一区二区三区四区av| 日韩黄色一级片| 九九爱精品视频| 91久久国产| 欧美日韩国产综合在线| 综合成人在线| 成人激情视频小说免费下载| 小早川怜子影音先锋在线观看| 久久人体大胆视频| 国产黄色在线| 亚洲男人第一av网站| 老熟妇高潮一区二区高清视频| 欧美日韩在线观看一区二区| 少妇一级淫片免费放中国 | 欧美黑人xxxⅹ高潮交| 国产视频第一区| 日韩精品中文字幕视频在线| va婷婷在线免费观看| 欧美日韩一区三区四区| www.国产色| 亚洲 欧美综合在线网络| 国产精品99久久久久久成人| 欧美激情自拍偷拍| 免费一级做a爰片久久毛片潮| 99天天综合性| 国产a级黄色片| 懂色av一区二区在线播放| 久久久久久久久久久久久久久国产 | 在线视频亚洲欧美| 国产香蕉在线| 亚洲日韩中文字幕| 国产在线黄色| 亚洲人高潮女人毛茸茸| 美女毛片在线看| 日韩激情视频在线| 亚洲AV成人无码一二三区在线| 精品福利在线导航| 国产1区在线观看| 精品国产免费一区二区三区香蕉| 99久久免费国产精精品| 欧美一区欧美二区| 精品久久久久成人码免费动漫| 91麻豆精品国产91久久久使用方法| 亚洲一卡二卡在线| 欧美精品tushy高清| 国产精品人妻一区二区三区| 717成人午夜免费福利电影| 国产女人爽到高潮a毛片| 日韩午夜在线播放| 亚洲精品97久久中文字幕无码| 日韩欧美国产成人一区二区| 成人黄色免费视频| 亚洲成人999| 青青视频在线观| 夜夜嗨av色综合久久久综合网| 天天在线视频色| 成人444kkkk在线观看| 亚洲婷婷噜噜| 91成品人片a无限观看| 欧美1级2级| 国产精品一区二区在线| 精品一区二区三区四区五区| av电影成人| 天天躁日日躁狠狠躁欧美| 日韩欧美一区二区三区四区| 日韩一区二区在线| 黄色网络在线观看| 亚洲欧洲一区| 99热手机在线| 国产伦精品一区二区三区视频青涩| 国产精品嫩草69影院| 93久久精品日日躁夜夜躁欧美| 最近中文字幕在线mv视频在线 | 夜夜添无码一区二区三区| 免费亚洲一区| 国产欧美精品一二三| 99久免费精品视频在线观看 | 日韩精品123| 日韩在线观看网址| 2024短剧网剧在线观看| 欧美专区中文字幕| 国产 日韩 欧美| 久久资源亚洲| 亚洲精品91| av片中文字幕| 国产成人h网站| 成熟人妻av无码专区| 亚洲综合色区另类av| 91porny九色| 亚洲成人久久网| 亚乱亚乱亚洲乱妇| 欧美一级免费看| 精品国产三区在线| 日本一区不卡| 亚洲激情视频| 亚洲一二三av| 久久久不卡影院| 国产亚洲精品av| 欧美日韩国产区一| 欧洲免费在线视频| 欧美极品少妇xxxxⅹ喷水| 国产精品99精品一区二区三区∴| 国产精品视频入口| 99久久综合狠狠综合久久aⅴ| 亚洲中文字幕无码专区| 国产乱人伦偷精品视频免下载| 成人在线一级片| 午夜精品一区二区三区免费视频| 国产精品无码白浆高潮| 中文字幕v亚洲ⅴv天堂| 中文字幕人成乱码在线观看| 成人综合色站| 欧美有码视频| 一起操在线视频| 国产日韩成人精品| 狠狠人妻久久久久久| 精品久久久三级丝袜| 91三级在线| 91免费看国产| 色综合色综合| 婷婷六月天在线| 国产亚洲1区2区3区| www.国产高清| 日韩毛片在线观看| 51漫画成人app入口| 高清国产在线一区| 欧美日韩亚洲国产精品| 日韩欧美理论片| |精品福利一区二区三区| 中文字幕无码乱码人妻日韩精品| 亚洲久久久久久久久久| 欧亚av在线| 国内一区二区三区在线视频| 在线看片日韩| 日b视频在线观看| 天天综合网天天综合色| 四虎精品一区二区三区| 韩日欧美一区二区| 欧美电影完整版在线观看| 免费毛片网站在线观看| 成人激情小说乱人伦| 国产情侣在线视频| 亚洲欧美在线播放| 成人看片网站| 亚洲成色www久久网站| 麻豆国产一区二区| 国产美女高潮视频| 欧美一区二区女人| 欧美aaaaaaa| 精品国产一区二区三区麻豆小说| 亚洲黑丝一区二区| 人妻熟女aⅴ一区二区三区汇编| 日韩欧美国产中文字幕| 东凛在线观看| 91精品久久久久久| 女人色偷偷aa久久天堂| 久久免费精品国产| 欧美日韩综合视频网址| 国产黄色免费在线观看| 国产欧美久久久久久| 欧美岛国激情| 波多野结衣三级视频| 黄色成人av网| av资源在线观看免费高清| 亚洲综合社区网| 亚洲伦伦在线| 美国黄色特级片| 精品日韩在线一区| 韩日成人影院| 丰满女人性猛交| eeuss国产一区二区三区| 国产91精品看黄网站在线观看| 自拍偷拍亚洲欧美| 成人av激情人伦小说| 国产成人精品无码播放| 亚洲视频免费看| 色播色播色播色播色播在线| 国产精品视频一区二区高潮| 欧美精选一区| 无码人妻aⅴ一区二区三区69岛| 91麻豆精品国产| 亚洲最大成人| 女人被男人躁得好爽免费视频| 久久久久久久久伊人| 国产视频一区二区三| 热99在线视频| 国色天香一区二区| 日本 欧美 国产| 国产丝袜精品第一页| 亚洲视频国产| gai在线观看免费高清| 欧美性生交大片免费|