最近因为工作需要,要改动mysql-java驱动Connector/J的部分源码,改动前需要先下载源码,改动后还需要编译打包生成可用jar包,本以为很简单,没想到步骤那么繁琐,为了以后使用方便,也为了分享给各位小伙伴,这里将详细的下载以及编译打包流程记录下来。
整体打包流程主要参考mysql官网,且打包版本为Connector/J 8.0.26:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-installing-source.html
第一步:准备环境
centos7,JDK1.8,Ant1.10.6
我一开始用的windows环境,但是最后编译出了一些问题,所以直接用的centos虚拟机。这里之所以用的centos7,是因为下载源码时有个选项对应该系统,而我的虚拟机也是这个版本。
JDK1.8是官网编译要求的最低版本。
Ant1.10.6也是官网要求使用的最低版本。
centos,JDK,Ant安装如果不熟悉可以上网搜下,这些不是编译的难点,所以这里不多介绍。
第二步:准备jar包
Connector/J源码里面依赖了一些外部的jar,如果想正常启动工程并且最后成功编译出jar,这里第三方依赖包是必不可少的,需要的jar如下:
ant-junitlauncher-1.10.6.jar
junit-jupiter-api-5.6.2.jar
junit-jupiter-engine-5.6.2.jar
junit-platform-commons-1.6.2.jar
junit-platform-engine-1.6.2.jarjunit-platform-launcher-1.6.2.jar
apiguardian-api-1.1.0.jar
opentest4j-1.2.0.jar
Javassist 3.27
protobuf-java-3.11.4.jar
c3p0-0.9.5.5.jar
slf4j-api-1.7.30.jar
hamcrest-2.2.jar
这些jar可以直接点击mysql官网后的下载链接跳转到指定页面进行下载:
除了上述下载方式之外,这些jar在maven官网上也可以下载到,只不过需要多留意两个点:
1、有很多类似的包,一定要确认好每个包的groupId、artifactId、version和官网一致,这里以ant-junitlauncher-1.10.6.jar为例:链接和maven地址如下:
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-junitlauncher</artifactId>
<version>1.10.6</version>
</dependency>
即下载链接artifact路径后“/”分隔符紧跟的三个信息分为为groupId、artifactId、version
2、在maven官网下载jar包正常情况是点击jar下载,如果不是jar也可以直接点击下载,如下:
第三步:下载源码
官网给出了三种下载源码的方式,这里我只展示其中一种我用的方式,即直接从官网下载,下载链接为:MySQL :: Download Connector/J 。页面选择为:
默认都是下载最新版本,如果想下载其它版本,则需要选择Archives选项,如下:
第四步:解压源码
上一步我们拿到的源码只是一个rpm包,要想拿到可用的源码还需要解压两层才行。解压是个很简单的过程,这里之所以拿出来讲下,是因为有些点可能被忽略从而阻塞我们的编译进程。首先将rpm包上传到虚拟机。其次使用如下命令解压:
rpm -ivh mysql-connector-java-8.0.26-1.el7.src.rpm --force --nodeps
最后的 --force --nodeps 加不加都可以,如果读完下面一段没找到rpm解压的包则可以加上
解压情况如下:
这个时候再看当前目录下竟然没有解压的包,肯定都以为没有解压成功。实际则不是,这个时候去当前用户目录下查看下是不是有rpm相关的解压包存在(至于为什么rpm解压后文件夹跑到了当前用户目录下,因为不是重点所以没花时间查,有知道的小伙伴可以留言告知下),我是root用户,此时用户目录下文件夹信息如下:
可以看到多了个rpmbuild文件夹,到这我们完成了获取源码的第一步,再有一步解压即可获得完整源码,此时我们进入rpmbuild/SOURCES 目录下可以看到 mysql-connector-java-8.0.26.tar.gz 文件,这是一个tar包,注意此时我们解压要用如下命令:
tar -xvf mysql-connector-java-8.0.26.tar.gz
如果使用 tar -zxvf则会报错,原因好像跟压缩的方式有关,这里跟我们编译的目标关联不大,故也没有深究原因,大家避开就好。至此我们获得了完整的源码,其结构信息如下:
第五步:启动项目工程,修改源码
这里仅仅为了测试简单打印了两条日志表明我们源码修改生效,对这一步不感兴趣的可以直接看下一步。
首先用IDEA打开源码工程,并在根目录下创建lib目录,随后将我们前面下载的依赖包放lib目录里,如下图:
因为源码需要依赖这些包,所以为了工程不各种报错,这里我们把lib里的包导入工程里,如下:
没选JDK的这里可以选择一下:
选中刚才复制到lib中的所有jar包,注意要全部选中:
除了导入依赖包之外,还需要在IDEA中标记源码文件夹,这样IDEA才能正常识别代码,标记如下:
此时我们就可以安装需要修改MySQL Connector/J驱动源码了,这里在查询前打印sql,查询后打印结果,代码修改如下:
@Override
public java.sql.ResultSet executeQuery(String sql) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
System.out.println("源码打印sql:" + sql);
...................
while (this.results.next()){
System.out.println("源码返回结果:" + this.results.getInt(1));
}
return this.results;
}
}
修改完成,接下来就是编译成jar包了
第六步:编译Connector/J源码包
我们将第四步获取的mysql-connector-java-8.0.26文件夹下的完整源码移动到自己想要放置的位置,随后在mysql-connector-java-8.0.26所在同级目录下创建一个文件夹用于存储第二步下载的依赖包,这里我创建文件夹为ant-extralibs,然后再将jar包导入,其目录信息如下:
随后再 mysql-connector-java-8.0.26 文件夹下创建 build.properties文件,并添加如下属性信息:
org.apache.hive.build.jdk=/opt/module/jdk1.8.0_251
org.apache.hive.extra.libs=/opt/mysqlbuild/ant-extralibs
此时mysql-connector-java-8.0.26 文件夹下src目录里存储的代码还是初始的源码,并不是我们第五步修改的源码,所以此时需要我们将第五步修改的代码替换到当前源码中,这里我采用整体替换src文件的方式进行替换,替换页面如下:
添加完成后运行如下命令进行编译打包:
ant dist
打包结果如下:
[root@hadoop mysql-connector-java-8.0.26]# ant dist
Buildfile: /opt/mysqlbuild/mysql-connector-java-8.0.26/build.xml
-extra-libs-check:
-jdk-check:
-compiler-check:
clean:
-load-info-properties:
[exec] Result: 128
[exec] Result: 128
[exec] Result: 128
[exec] Result: 128
-init-copy-common:
[mkdir] Created dir: /opt/mysqlbuild/mysql-connector-java-8.0.26/build
[copy] Copying 551 files to /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT
-init-filter-license:
-init-no-crypto:
-init-license-headers:
-init-copy:
-init-notices-commercial:
-init-notices-gpl:
[get] Getting: file:./LICENSE
[get] To: /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT/LICENSE
[get] .
[copy] Copying 1 file to /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT
-init-info-files:
[echo] ## INFO_BIN ##
[echo] build-date: 2022-01-12 20:42:22 -0500
[echo] os-info: Linux amd64 3.10.0-1160.el7.x86_64
[echo] compiler: javac 1.8.0_251
[echo] build-tool: Apache Ant(TM) version 1.10.6 compiled on May 2 2019
[echo] ## INFO_SRC ##
[echo] version: 8.0.26-SNAPSHOT
[echo] branch: ${revinfo.branch}
[echo] date: ${revinfo.date}
[echo] commit: ${revinfo.commit}
[echo] short: ${revinfo.short}
init:
-clean-output:
compile-driver:
[echo] Compiling MySQL Connector/J JDBC implementation with '/opt/module/jdk1.8.0_251' to 'build/mysql-connector-java-8.0.26-SNAPSHOT'
[javac] Compiling 529 source files to /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT
[javac] Creating empty /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT/com/mysql/cj/xdevapi/package-info.class
[javac] Creating empty /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT/com/mysql/cj/x/protobuf/package-info.class
[java] Applying CommonChecks.
[java] Applying TranslateExceptions.
[java] Applying AddMethods.
-compile-integration-c3p0:
[echo] Compiling MySQL Connector/J-c3p0 integration with '/opt/module/jdk1.8.0_251' to 'build/mysql-connector-java-8.0.26-SNAPSHOT'
[javac] Compiling 1 source file to /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT
compile-integration:
compile:
dist:
[mkdir] Created dir: /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT/META-INF/services
[copy] Copying 4 files to /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT/META-INF
[jar] Building jar: /opt/mysqlbuild/mysql-connector-java-8.0.26/build/mysql-connector-java-8.0.26-SNAPSHOT/mysql-connector-java-8.0.26-SNAPSHOT.jar
BUILD SUCCESSFUL
Total time: 17 seconds
此时源码包路径下有个build文件夹,逐层点击进去即可看到 mysql-connector-java-8.0.26-SNAPSHOT.jar文件。至此我们获得了符合自己需求的驱动包。
第七步:测试验证
上一步虽然打包成功了,但是我们的修改具体有没有生效还有待考证,这里就是简单验证下,首先创建工程,随后引入我们的jar包,工程信息如下:
最后编辑验证代码如下:
public static void main(String[] args) {
String url = "jdbc:mysql://172.21.205.134:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT";
String user = "root";
String password = "root";
String sql = "select count(*) from tt";
try {
Class.forName("com.mysql.cj.jdbc.Driver"); //jdbc mysql连接驱动
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (
Connection conn = DriverManager.getConnection(url, user, password);
//createStatement()方法一般不加参数,其获取的resultSet只能读取一遍。因为源码中已经读取了一遍resultset,这里为了再重新读取一次,故开始resultSet游标重置功能
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
) {
ResultSet resultSet = stmt.executeQuery(sql);
//重置游标到第一个结果
resultSet.first();
System.out.println("客户端查询结果:" + resultSet.getInt(1));
//因为使用了resultSet.first()方法置位游标到第一个元素,所以这里next方法会跳到第二个结果,但是返回的结果只有一个,所以while循环内的代码不会执行,不信的可以放开注释试试
// while (resultSet.next()) {
// System.out.println(resultSet.getInt(1));
// }
} catch (Exception e) {
System.out.println(e);
}
}
上述代码即简单查询下表内的行数,代码运行结果如下:
可以看到,我们再源码中添加的两行日志正常打印出来了,这也证明了我们的源码修改生效了。