老铁们好,我是V,今天我们简单聊聊怎么修改jar包中的类
背景
我们有时候需要修改jar中的某个class,有时候是因为需要修复某些bug,有时候是定制化开发
例如为了实现es的索引动态修改索引中的压缩算法,我们需要修改lucene-core中的IndexWriter.class这个类
解决方案
方法一、解压jar包将修改后的class放进去重新压缩
这个方法虽然可行,但是显得很蠢
方法二、下载源码自己编译修改
从github上下载源码后,自己修改源码,重新编译,这当然是最彻底的解决方案。但是lucene-core 7.7.3是用ant编译的,是我太菜了,我试了很多次,都没编译成功。
方法三、maven-dependency-plugin插件替换class打包
这也是本文重点介绍的方法
我们建好java项目后,将IndexWriter.java源码复制出来,放到指定的package修改好后放到指定的package
对应的插件设置也很简单
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<executions>
<execution>
<id>replace-custom-class</id>
<phase>generate-sources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
这样插件就会将lucene-core的class解压,然后将我们自定义的IndexWriter编译后覆盖原生的IndexWriter.class
完整pom.xml
<?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.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>${lucene-core.version}-0.0.1-SNAPSHOT</version>
<properties>
<java.version>8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-compiler-plugin.encoding>UTF-8</maven-compiler-plugin.encoding>
<maven-dependency-plugin.version>3.6.0</maven-dependency-plugin.version>
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
<lucene-core.version>7.7.3</lucene-core.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>${lucene-core.version}</version>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
<id>xxx-snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://xxx.com/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>xxx-releases</id>
<name>Nexus Release Repository</name>
<url>http://xxx.com/nexus/content/repositories/releases/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${maven-compiler-plugin.encoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<executions>
<execution>
<id>replace-custom-class</id>
<phase>generate-sources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
执行命令打包
mvn clean install -DskipTests
这样得到的jar就可以直接用了
遇到的问题
你以为这就结束了吗?虽然我们功能实现了,但是jar包中的其他的类的源码无法查看了,虽然不影响使用,但是有些膈应。
源码无法查看
虽然通过上面的方式我们得到了定制化的jar lucene-core-7.7.3-0.0.1-SNAPSHOT.jar 但是没有源码
于是我们添加
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<attach>true</attach>
</configuration>
</execution>
</executions>
</plugin>
我们看看下源码
麻了,这里面只有我们修改的类的源码,虽然不影响使用,但是后续我们debug的时候会非常麻。
查了很久的资料,发现maven-source-plugin没有办法指定源码的位置,于是就采用了另外一个不太优雅的方法
打包源码
首先我们在目录下另外建一个lucene-core-7.7.3-sources
里面不需要任何内容
方案
-
generate-sources阶段使用maven-dependency-plugin解压lucene-core-sources.jar到lucene-core-7.7.3-sources/src/main/java文件夹
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>${maven-dependency-plugin.version}</version> <executions> <execution> <id>source-unpack</id> <phase>generate-sources</phase> <goals> <goal>unpack</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <overWrite>false</overWrite> <classifier>sources</classifier> <outputDirectory>${project.basedir}/src/main/java</outputDirectory> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin>
-
使用exec-maven-plugin拷贝lucene-core-7.7.3中的源码到lucene-core-7.7.3-sources/src/main/java目录下
这个插件主要作用
- clean阶段清理lucene-core-7.7.3-sources/src/main文件夹
- generate-sources阶段拷贝lucene-core-7.7.3/src/main/java/org/apache/lucene/index/IndexWriter.java到lucene-core-7.7.3-sources对应目录
- compile阶段清理lucene-core-7.7.3-sources/src/main/java目录
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.2.0</version> <executions> <!-- source.jar生成之前,clean阶段清理main/java文件夹 --> <execution> <id>clean-sources</id> <phase>clean</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>bash</executable> <arguments> <argument>-c</argument> <argument>rm -rf ${project.basedir}/src/main/</argument> </arguments> </configuration> </execution> <!-- 从lucene-core-7.7.3中拷贝源码到main/java文件夹 --> <execution> <id>copy-custom-sources</id> <phase>generate-sources</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>bash</executable> <arguments> <argument>-c</argument> <argument>cp -r ${project.basedir}/../lucene-core-${lucene-core.version}/src/main/java ${project.basedir}/src/main/</argument> </arguments> </configuration> </execution> <!-- compile阶段清理main/java文件夹 --> <execution> <id>clean-sources-after-compile</id> <phase>compile</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>bash</executable> <arguments> <argument>-c</argument> <argument>rm -rf ${project.basedir}/src/main/</argument> </arguments> </configuration> </execution> </executions> </plugin>
-
使用maven-source-plugin打包源码
这个大家都熟悉,就懒得贴了
完整pom.xml如下
<?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.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>${lucene-core.version}-0.0.1-SNAPSHOT</version>
<properties>
<java.version>8</java.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-compiler-plugin.encoding>UTF-8</maven-compiler-plugin.encoding>
<maven-dependency-plugin.version>3.6.0</maven-dependency-plugin.version>
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
<lucene-core.version>7.7.3</lucene-core.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>${lucene-core.version}</version>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
<id>xxx-snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://xxx.com/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>xxx-releases</id>
<name>Nexus Release Repository</name>
<url>http://xxx.com/nexus/content/repositories/releases/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<skip>true</skip>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${maven-compiler-plugin.encoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<attach>true</attach>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<executions>
<execution>
<id>source-unpack</id>
<phase>generate-sources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<overWrite>false</overWrite>
<classifier>sources</classifier>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.2.0</version>
<executions>
<!-- source.jar生成之前,clean阶段清理main/java文件夹 -->
<execution>
<id>clean-sources</id>
<phase>clean</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bash</executable>
<arguments>
<argument>-c</argument>
<argument>rm -rf ${project.basedir}/src/main/</argument>
</arguments>
</configuration>
</execution>
<!-- 从lucene-core-7.7.3中拷贝源码到main/java文件夹 -->
<execution>
<id>copy-custom-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bash</executable>
<arguments>
<argument>-c</argument>
<argument>cp -r ${project.basedir}/../lucene-core-${lucene-core.version}/src/main/java ${project.basedir}/src/main/</argument>
</arguments>
</configuration>
</execution>
<!-- source.jar生成完毕,compile阶段清理main/java文件夹 -->
<execution>
<id>clean-sources-after-compile</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bash</executable>
<arguments>
<argument>-c</argument>
<argument>rm -rf ${project.basedir}/src/main/</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
执行命令打包source.jar
这里的compile是为了触发clean-sources-after-compile
mvn clean source:jar compile
我看下打包好的sources jar
舒服了
推送源码
但是问题又来了
这样本来一个项目被我们分成了两个,这时候推送分两次使用mvn clean deploy -DskipTests
推送jar包,特别是snapshot的jar会有maven-metadata.xml
<metadata modelVersion="1.1.0">
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>7.7.3-0.0.1-SNAPSHOT</version>
<versioning>
<snapshot>
<timestamp>20240811.061414</timestamp>
<buildNumber>17</buildNumber>
</snapshot>
<lastUpdated>20240811061414</lastUpdated>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>7.7.3-0.0.1-20240811.061414-17</value>
<updated>20240811061414</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
<value>7.7.3-0.0.1-20240811.061414-17</value>
<updated>20240811061414</updated>
</snapshotVersion>
<snapshotVersion>
<classifier>sources</classifier>
<extension>jar</extension>
<value>7.7.3-0.0.1-20240811.061532-17</value>
<updated>20240811061532</updated>
</snapshotVersion>
</snapshotVersions>
</versioning>
</metadata>
我们会发现jar的版本和sources jar的版本不一致,导致在idea中无法匹配
所以需要一次性将jar和sources jar一起推送到maven仓库才行
经过一番查阅资料后发现可以用mvn命令可以解决问题
安装sources jar到本地
mvn install:install-file \
-Dfile=$PWD/lucene-core-7.7.3-sources/target/lucene-core-7.7.3-0.0.1-SNAPSHOT-sources.jar \
-DgroupId=org.apache.lucene \
-DartifactId=lucene-core \
-Dversion=7.7.3-0.0.1-SNAPSHOT \
-Dpackaging=jar \
-Dclassifier=sources
同时推送jar和source.jar
好了,注意看,这行命令就是这篇文章最有价值的地方了
使用-Dfile指定jar的路径
使用-Dfiles指定source jar的路径,使用-Dtypes指定source jar的后缀
```bash
mvn deploy:deploy-file \
-DgroupId=org.apache.lucene \
-DartifactId=lucene-core \
-Dversion=7.7.3-0.0.1-SNAPSHOT \
-Dpackaging=jar \
-Dfile=$PWD/lucene-core-7.7.3/target/lucene-core-7.7.3-0.0.1-SNAPSHOT.jar \
-Dclassifiers=sources \
-Dtypes=jar \
-Dfiles=$PWD/lucene-core-7.7.3-sources/target/lucene-core-7.7.3-0.0.1-SNAPSHOT-sources.jar \
-DrepositoryId=xxx-snapshots \
-Durl=http://xxx.com/nexus/content/repositories/snapshots/
```
结语
收工搞定,虽然这个方法还是不够优雅,但是好歹也不是太高频的操作,解决了打包源码的问题凑合用得了。
如果大佬们有更好的方法,请在评论区教教我,嘿嘿。