最近因为工作需要,要改动mysql-java驱动Connector/J的部分源码,改动前需要先下载源码,改动后还需要编译打包生成可用jar包,本以为很简单,没想到步骤那么繁琐,为了以后使用方便,也为了分享给各位小伙伴,这里将详细的下载以及编译打包流程记录下来。

整体打包流程主要参考mysql官网,且打包版本为Connector/J 8.0.26https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-installing-source.html

mysql驱动pom文件 mysql驱动源码_Connector/J

 第一步:准备环境

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.jar
junit-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官网后的下载链接跳转到指定页面进行下载:

mysql驱动pom文件 mysql驱动源码_java_02

mysql驱动pom文件 mysql驱动源码_java_03

除了上述下载方式之外,这些jar在maven官网上也可以下载到,只不过需要多留意两个点:

1、有很多类似的包,一定要确认好每个包的groupId、artifactId、version和官网一致,这里以ant-junitlauncher-1.10.6.jar为例:链接和maven地址如下:

mysql驱动pom文件 mysql驱动源码_java_04


 <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驱动pom文件 mysql驱动源码_java_05

 第三步:下载源码

官网给出了三种下载源码的方式,这里我只展示其中一种我用的方式,即直接从官网下载,下载链接为:MySQL :: Download Connector/J 。页面选择为:

mysql驱动pom文件 mysql驱动源码_mysql_06

mysql驱动pom文件 mysql驱动源码_mysql_07

 默认都是下载最新版本,如果想下载其它版本,则需要选择Archives选项,如下:

mysql驱动pom文件 mysql驱动源码_Connector/J_08

 

mysql驱动pom文件 mysql驱动源码_源码编译_09

 第四步:解压源码

上一步我们拿到的源码只是一个rpm包,要想拿到可用的源码还需要解压两层才行。解压是个很简单的过程,这里之所以拿出来讲下,是因为有些点可能被忽略从而阻塞我们的编译进程。首先将rpm包上传到虚拟机。其次使用如下命令解压:

rpm -ivh mysql-connector-java-8.0.26-1.el7.src.rpm  --force --nodeps
最后的 --force --nodeps 加不加都可以,如果读完下面一段没找到rpm解压的包则可以加上

解压情况如下:

mysql驱动pom文件 mysql驱动源码_Connector/J_10

这个时候再看当前目录下竟然没有解压的包,肯定都以为没有解压成功。实际则不是,这个时候去当前用户目录下查看下是不是有rpm相关的解压包存在(至于为什么rpm解压后文件夹跑到了当前用户目录下,因为不是重点所以没花时间查,有知道的小伙伴可以留言告知下),我是root用户,此时用户目录下文件夹信息如下:

mysql驱动pom文件 mysql驱动源码_mysql驱动pom文件_11

可以看到多了个rpmbuild文件夹,到这我们完成了获取源码的第一步,再有一步解压即可获得完整源码,此时我们进入rpmbuild/SOURCES 目录下可以看到 mysql-connector-java-8.0.26.tar.gz 文件,这是一个tar包,注意此时我们解压要用如下命令:

tar -xvf mysql-connector-java-8.0.26.tar.gz

如果使用 tar -zxvf则会报错,原因好像跟压缩的方式有关,这里跟我们编译的目标关联不大,故也没有深究原因,大家避开就好。至此我们获得了完整的源码,其结构信息如下:

mysql驱动pom文件 mysql驱动源码_源码编译_12

第五步:启动项目工程,修改源码

这里仅仅为了测试简单打印了两条日志表明我们源码修改生效,对这一步不感兴趣的可以直接看下一步。

首先用IDEA打开源码工程,并在根目录下创建lib目录,随后将我们前面下载的依赖包放lib目录里,如下图:

mysql驱动pom文件 mysql驱动源码_mysql_13

因为源码需要依赖这些包,所以为了工程不各种报错,这里我们把lib里的包导入工程里,如下:

mysql驱动pom文件 mysql驱动源码_mysql_14

没选JDK的这里可以选择一下:

 

mysql驱动pom文件 mysql驱动源码_源码编译_15

mysql驱动pom文件 mysql驱动源码_源码编译_16

选中刚才复制到lib中的所有jar包,注意要全部选中

mysql驱动pom文件 mysql驱动源码_mysql驱动pom文件_17

 除了导入依赖包之外,还需要在IDEA中标记源码文件夹,这样IDEA才能正常识别代码,标记如下:

mysql驱动pom文件 mysql驱动源码_mysql_18

此时我们就可以安装需要修改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驱动pom文件 mysql驱动源码_Connector/J_19

随后再 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文件的方式进行替换,替换页面如下:

mysql驱动pom文件 mysql驱动源码_mysql_20


添加完成后运行如下命令进行编译打包:

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包,工程信息如下:

mysql驱动pom文件 mysql驱动源码_mysql驱动pom文件_21

最后编辑验证代码如下:

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);
	}
	
}

上述代码即简单查询下表内的行数,代码运行结果如下:

mysql驱动pom文件 mysql驱动源码_java_22

可以看到,我们再源码中添加的两行日志正常打印出来了,这也证明了我们的源码修改生效了。