如何全局搜索maven项目中引用jar包中的文件
在开发过程中,遇到过一件事,当时本地启动服务,页面调用远程接口的时候一直报找不到服务,但是又找不到哪里错误,这个时候发现启动过程中,打印了一段信息,觉得有可能是跟这边有关,这段信息是System.out直接打印出来的(代码不规范),找不到是哪个类跑出来的,是引用的jar包里面的,全局Crtl+shift+F也搜不到jar包里面的,一步步跟踪,代码太多,很难找到(虽然到最后跟这行信息没关系,问写源代码的同事说这段信息可以忽略,原因在于网络vpn的问题)。
这个时候就想到了一个问题,如何全局搜索maven项目中引用jar包中的文件。
解决这个问题
1、首先需要找到项目引用的所有jar包
2、对jar包进行反编译
3、内容搜索
最后解决过程如下:
1、找到项目工程引用的jar包
mvn dependency:copy-dependencies -DoutputDirectory=/Users/taoxuefeng/mvnlib
使用该命令可以将项目中引用的所有jar包拷贝到指定目录
2、反编译
反编译,idea自带反编译,jd-gui也支持,可惜那些都是页面化的,不能程序控制,这里使用的是crf反编译
3、内容搜索
这里就不多说了,很简单
代码如下:
1、pom
指定crf反编译依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>cfrtest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.benf</groupId>
<artifactId>cfr</artifactId>
<version>0.151</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
2、反编译核心类
输入jar包文件夹地址,和反编译代码存放地址,会自动进行反编译
package com.taoge.cfrtest;
/**
* Desc:
*
* @author taoxuefeng
* @date 2021/9/24
*/
import org.benf.cfr.reader.api.CfrDriver;
import org.benf.cfr.reader.util.getopt.OptionsImpl;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* @author hengyunabc 2018-11-16
*/
public class Decompiler {
public static Long cfr(String source, String targetPath) throws IOException {
Long start = System.currentTimeMillis();
List<String> files = new ArrayList<>();
File file = new File(source);
if (file.isDirectory()) {
File[] fileList = file.listFiles();
for (File temp : fileList) {
files.add(temp.getAbsolutePath());
}
} else {
files.add(source);
}
// target dir
HashMap<String, String> outputMap = new HashMap<>();
outputMap.put("outputdir", targetPath);
OptionsImpl options = new OptionsImpl(outputMap);
CfrDriver cfrDriver = new CfrDriver.Builder().withBuiltOptions(options).build();
cfrDriver.analyse(files);
Long end = System.currentTimeMillis();
return (end - start);
}
}
2、搜索结果
搜索结果类,记录了文件名,绝对路径地址,开始结束时间,以及匹配到的文件行
package com.taoge.cfrtest;
import java.util.List;
/**
* Desc:
*
* @author taoxuefeng
* @date 2021/11/19
*/
public class SearchResult {
private String fileName;
private String absolutePath;
private List<Integer> lineList;
private Long startTime;
private Long endTime;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getAbsolutePath() {
return absolutePath;
}
public void setAbsolutePath(String absolutePath) {
this.absolutePath = absolutePath;
}
public List<Integer> getLineList() {
return lineList;
}
public void setLineList(List<Integer> lineList) {
this.lineList = lineList;
}
public Long getStartTime() {
return startTime;
}
public void setStartTime(Long startTime) {
this.startTime = startTime;
}
public Long getEndTime() {
return endTime;
}
public void setEndTime(Long endTime) {
this.endTime = endTime;
}
}
3、搜索
这个就不多说了,反编译后得到一堆文件,对里面的文件递归搜索,并生成搜索结果
package com.taoge.cfrtest;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Desc:
*
* @author taoxuefeng
* @date 2021/11/18
*/
public class SearchFile {
public static List<SearchResult> search(String targetPath, String searchContent) {
List<SearchResult> searchResults = new ArrayList<>();
File file = new File(targetPath);
if (file.isDirectory()) {
for (File childFile : file.listFiles()) {
if (childFile.isFile()) {
SearchResult result = search(childFile, searchContent);
if (Objects.nonNull(result)) {
searchResults.add(result);
}
} else {
searchResults.addAll(search(childFile.getAbsolutePath(), searchContent));
}
}
} else {
SearchResult result = search(file, searchContent);
if (Objects.nonNull(result)) {
searchResults.add(result);
}
}
return searchResults;
}
private static SearchResult search(File file, String searchContent) {
try {
SearchResult searchResult = new SearchResult();
searchResult.setAbsolutePath(file.getAbsolutePath());
searchResult.setFileName(file.getName());
searchResult.setStartTime(System.currentTimeMillis());
List<String> contentLines = FileUtils.readLines(file, "utf-8");
if (Objects.nonNull(contentLines)) {
List<Integer> lineResultList = new ArrayList<>();
for (int i = 0; i < contentLines.size(); i++) {
String line = contentLines.get(i);
if (Objects.nonNull(line) && line.contains(searchContent)) {
lineResultList.add(i + 1);
}
}
if (lineResultList.size() > 0) {
searchResult.setLineList(lineResultList);
searchResult.setEndTime(System.currentTimeMillis());
return searchResult;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
4、main方法
指定上面mvn生成的目录地址,输出反编译文件地址,以及搜索的内容
package com.taoge.cfrtest;
import java.io.IOException;
import java.util.List;
/**
* Desc:
*
* @author taoxuefeng
* @date 2021/11/19
*/
public class Main {
private static final String sourceDir = "/Users/taoxuefeng/mvnlib";
private static final String targetDir = "./cfr_output_jar";
private static final String searchContent = "this.putQueryParameter";
public static void main(String[] args) throws IOException {
Long time = Decompiler.cfr(sourceDir, targetDir);
System.out.println(String.format("反编译时间: %dms", time));
Long startTime = System.currentTimeMillis();
List<SearchResult> searchResults = SearchFile.search(targetDir, searchContent);
Long endTime = System.currentTimeMillis();
System.out.println(String.format("搜索时间: %dms", (endTime - startTime)));
for (SearchResult searchResult : searchResults) {
System.out.println("搜索结果--------------");
System.out.println(searchResult.getAbsolutePath());
System.out.println(searchResult.getFileName());
System.out.println(searchResult.getLineList());
}
}
}
5、运行