背景
通过官方提供的 repeater 的下载链接,并不能够在sandbox启动时,加载进行,我们可以看下sandbox的日志截图
但是如果通过源码的repeater进行安装后,就能够成功加载到repeater。
分析
这是个很奇怪的问题,想要分析这个,我们就要确认下通过官方的脚本安装跟源码安装的差异在哪了。
官方的shell脚本
#!/usr/bin/env bash
typeset SANDBOX_HOME=${HOME}/sandbox
typeset MODULE_HOME=${HOME}/.sandbox-module
# exit shell with err_code
# $1 : err_code
# $2 : err_msg
exit_on_err()
{
[[ ! -z "${2}" ]] && echo "${2}" 1>&2
exit ${1}
}
main(){
echo "====== begin to install sandbox and repeater module ======";
echo "====== step 0 begin to download sandbox package ======";
curl -s https://github.com/alibaba/jvm-sandbox-repeater/releases/download/v1.0.0/sandbox-1.3.3-bin.tar | tar xz -C ${HOME} || exit_on_err 1 "extract sandbox failed"
echo "====== step 1 begin to download repeater module package ======";
if [ ! -d ${MODULE_HOME} ]; then
mkdir -p ${MODULE_HOME} || exit_on_err 1 "permission denied mkdir ${MODULE_HOME}"
fi
curl -s https://github.com/alibaba/jvm-sandbox-repeater/releases/download/v1.0.0/repeater-stable-bin.tar | tar xz -C ${MODULE_HOME} || exit_on_err 1 "extract repeater failed"
echo "====== install finished ======";
}
main
从上面可以看出来,其实就是下载两个文件,分别解压到对应的目录下就好了。
那我们再看下通过repeater源码进行执行 install-local.sh
的逻辑
#!/usr/bin/env bash
# repeater's target dir
REPEATER_TARGET_DIR=../target/repeater
# exit shell with err_code
# $1 : err_code
# $2 : err_msg
exit_on_err()
{
[[ ! -z "${2}" ]] && echo "${2}" 1>&2
exit ${1}
}
# package
sh ./package.sh || exit_on_err 1 "install failed cause package failed"
# extract sandbox to ${HOME}
curl -s https://github.com/alibaba/jvm-sandbox-repeater/releases/download/v1.0.0/sandbox-1.3.3-bin.tar | tar x -C ${HOME} || exit_on_err 1 "extract sandbox failed"
# copy module to ~/.sandbox-module
mkdir -p ${HOME}/.sandbox-module || exit_on_err 1 "permission denied, can not mkdir ~/.sandbox-module"
cp -r ${REPEATER_TARGET_DIR}/* ${HOME}/.sandbox-module || exit_on_err 1 "permission denied, can not copy module to ~/.sandbox-module"
我们可以看到这里的过程其实就是先进行打包repeater, 然后在下载sandbox, 再将打包后的repeater的内容,复制一份到 sandbox-module
目录下。这里其实是有差异的,一个是解压压缩包,一个是直接复制目录的情况。
这里如果细致的话,就会发现一个明显不一样的地方了。
通过官方的shell脚本安装以后,得到的 .sandbox-module
目录下是一个repeater
的目录
而 通过源码安装得到的其实是不一样的
但是官方的得到的目录进行的一个层级一个 得到的就是相同的目录了.
这就是问题的根因了,但是为什么多一个目录,就导致没有办法被加载呢,其实这个我们可以尝试去看下sandbox的逻辑。
ModuleLibLoader.java
private File[] listModuleJarFileInLib() {
final File[] moduleJarFileArray = toModuleJarFileArray();
Arrays.sort(moduleJarFileArray);
logger.info("loading module-lib={}, found {} module-jar files : {}",
moduleLibDir,
moduleJarFileArray.length,
join(moduleJarFileArray, ",")
);
return moduleJarFileArray;
}
我们可以知道,加载module-lib成功就会有这样子的内容打印,所以其实关键就是
private File[] toModuleJarFileArray() {
if (moduleLibDir.exists()
&& moduleLibDir.isFile()
&& moduleLibDir.canRead()
&& StringUtils.endsWith(moduleLibDir.getName(), ".jar")) {
return new File[]{
moduleLibDir
};
} else {
return convertFileCollectionToFileArray(
listFiles(moduleLibDir, new String[]{"jar"}, false)
);
}
}
listFiles(moduleLibDir, new String[]{"jar"}, false)
是列出对应目录下所有jar包的问题,但是关键是第三个参数是false,其实就是不递归遍历,所以它只会获取到第一层级的目录,所以这就导致了如果目录多一个repeater以后,就没有办法,加载repeater了。