在这里介绍一种快速编译和修改jar里面特定class文件的方法, 本质上是对javac 、java、zip命令的综合使用。 在某些场景,能极大地提高部署和上线效率, 但是仅适用于少数为了快速调试、对外上线的特定业务场景。但是, 在正规的工程管理里面,仍然需要按项目开发和代码管理规范来!

前提知识

  1. jar文件本质是采用zip压缩的zip包,允许使用 zip、unzip命令对jar文件进行操作, 具体自己看man手册
  2. javac 只需要依赖的环境(依赖的环境变量、jar classpath )完整即可正常对一个工程或java文件进行编译

需求场景

以编译 HDP自带的 ranger unixusersync包为例, ranger的源代码见:https://github.com/apache/ranger/tree/ranger-0.5.2-rc1/

需要修改下面这个文件, 改动里面的默认成参数,加快自动同步LDAP用户信息到ranger的频率(默认是1小时):

1
2
3
// 路径:  org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java

private static final long UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_LDAP_DEFAULT_VALUE = 3600000L;”

操作步骤

  1. 在HDP安装目录,找到目标的ranger jar文件为: unixusersync-0.5.0.2.4.2.0-258.jar

  2. 拷贝jar重命名为 “unixusersync-0.5.0.2.4.2.0-258_sugan.jar” , 然后删除这个拷贝的jar里面指定的class文件

1
2
[root@orochihdp1 dist]# cp unixusersync-0.5.0.2.4.2.0-258.jar  unixusersync-0.5.0.2.4.2.0-258_sugan.jar
[root@orochihdp1 dist]# zip -d unixusersync-0.5.0.2.4.2.0-258_sugan.jar '/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.class'
  1. 修改UserGroupSyncConfig.java 里面的值
1
2
private static final long UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_LDAP_DEFAULT_VALUE = 60000L;”      
// 改成 60000L,加快自动同步LDAP用户信息到ranger的频率,默认是1小时
  1. 编译:
1
2
3
# 路径: root@orochihdp1:/usr/hdp/current/ranger-usersync/dist

javac -Xlint:unchecked -cp /usr/hdp/current/ranger-usersync/lib/commons-cli-1.2.jar:/usr/hdp/current/ranger-usersync/lib/commons-codec-1.9.jar:/usr/hdp/current/ranger-usersync/lib/commons-collections-3.2.2.jar:/usr/hdp/current/ranger-usersync/lib/commons-configuration-1.10.jar:/usr/hdp/current/ranger-usersync/lib/commons-csv-1.0.jar:/usr/hdp/current/ranger-usersync/lib/commons-httpclient-3.1.jar:/usr/hdp/current/ranger-usersync/lib/commons-io-2.4.jar:/usr/hdp/current/ranger-usersync/lib/commons-lang-2.6.jar:/usr/hdp/current/ranger-usersync/lib/commons-logging-1.2.jar:/usr/hdp/current/ranger-usersync/lib/credentialbuilder-0.5.0.2.4.2.0-258.jar:/usr/hdp/current/ranger-usersync/lib/gson-2.2.4.jar:/usr/hdp/current/ranger-usersync/lib/guava-11.0.2.jar:/usr/hdp/current/ranger-usersync/lib/hadoop-auth-2.7.1.2.4.2.0-258.jar:/usr/hdp/current/ranger-usersync/lib/hadoop-common-2.7.1.2.4.2.0-258.jar:/usr/hdp/current/ranger-usersync/lib/htrace-core-3.1.0-incubating.jar:/usr/hdp/current/ranger-usersync/lib/jersey-bundle-1.17.1.jar:/usr/hdp/current/ranger-usersync/lib/log4j-1.2.17.jar:/usr/hdp/current/ranger-usersync/lib/ranger-util-0.5.0.2.4.2.0-258.jar:/usr/hdp/current/ranger-usersync/lib/slf4j-api-1.7.5.jar:unixauthservice-0.5.0.2.4.2.0-258.jar:**./unixusersync-0.5.0.2.4.2.0-258_sugan.jar ** ./org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
  1. 把编译出来的class文件打进jar
1
zip -ru unixusersync-0.5.0.2.4.2.0-258_sugan.jar org/
  1. 把新的jar替换掉原来的jar( 记得备份旧的), 重启ranger

总结

上面演示了这种方法, 体现了对Apache ranger这个组件的源码进行修改的便利性, 帮助我们省去了完整的ranger工程项目下载和本地搭建、 本地编译打包(这个过程还需要下载大量依赖的其他包, 而且编译时间也颇久), 节约了大量的时间。

借助这种猥琐姿势, 我们能在以下场景中提高我们的效率:

  • 开源组件源码修改和编译: Hadoop、spark、yarn等等只要有对标版本的源码, 我们能快速修改某个jar的源代码和上线
  • 线上平台调试: 对一些问题的调试, 可以临时写个java, 在线上环境(例如跳板机)编译和运行后做 debug
  • 简单的逆向和破解场景: 这个方法同样适用, 前提是可反编译出目标代码并且目标的jar没做额外的加固和授权, 例如大部分第三方插件如 Jira a插件的破解