由于业务需要,使用springboot连接Hive-metastore service服务获取hive元数据,连接方式可参考Java调用Hive-metastore接口_天天乐见的笔记本-CSDN博客 这篇文章。
根据文章中的方法配置,并使用hive-site.xml配置文件的方式连接Hive-metastore service服务后,发现在IDE中能够正常访问Hive的元数据服务,但是将springboot服务打成jar包后出现了报错:
URI is not hierarchical
DirectJDKLog log Servlet.service() for servlet [dispatcherServlet] in context with path [/server] threw exception [Handler dispatch failed; nested exception is java.lang.ExceptionInInitializerError] with root cause java.lang.IllegalArgumentException: URI is not hierarchical
at java.io.File.<init>(Unknown Source)
at org.apache.hadoop.hive.conf.HiveConf.findConfigFile(HiveConf.java:171)
at org.apache.hadoop.hive.conf.HiveConf.<clinit>(HiveConf.java:139)
根据上述报错,这是由于org.apache.hive:hive-common 中HiveConf初始化造成的问题:当使用下属语句创建HiveConf时
HiveConf hiveConf = new HiveConf();
根据HiveConf.java源码,会进行静态块初始化:
static {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = HiveConf.class.getClassLoader();
}
hiveDefaultURL = classLoader.getResource("hive-default.xml");
// Look for hive-site.xml on the CLASSPATH and log its location if found.
hiveSiteURL = findConfigFile(classLoader, "hive-site.xml", true);
hivemetastoreSiteUrl = findConfigFile(classLoader, "hivemetastore-site.xml", false);
hiveServer2SiteUrl = findConfigFile(classLoader, "hiveserver2-site.xml", false);
for (ConfVars confVar : ConfVars.values()) {
vars.put(confVar.varname, confVar);
}
Set<String> llapDaemonConfVarsSetLocal = new LinkedHashSet<>();
populateLlapDaemonVarsSet(llapDaemonConfVarsSetLocal);
llapDaemonVarsSet = Collections.unmodifiableSet(llapDaemonConfVarsSetLocal);
}
其中的findConfile方法用来查找hive-site.xml配置:
private static URL findConfigFile(ClassLoader classLoader, String name, boolean doLog) {
URL result = classLoader.getResource(name);
if (result == null) {
String confPath = System.getenv("HIVE_CONF_DIR");
result = checkConfigFile(new File(confPath, name));
if (result == null) {
String homePath = System.getenv("HIVE_HOME");
String nameInConf = "conf" + File.pathSeparator + name;
result = checkConfigFile(new File(homePath, nameInConf));
if (result == null) {
URI jarUri = null;
try {
jarUri = HiveConf.class.getProtectionDomain().getCodeSource().getLocation().toURI();
} catch (Throwable e) {
if (l4j.isInfoEnabled()) {
l4j.info("Cannot get jar URI", e);
}
System.err.println("Cannot get jar URI: " + e.getMessage());
}
result = checkConfigFile(new File(new File(jarUri).getParentFile(), nameInConf));
}
}
}
if (doLog && l4j.isInfoEnabled()) {
l4j.info("Found configuration file " + result);
}
return result;
}
当执行到这行代码时
result = checkConfigFile(new File(new File(jarUri).getParentFile(), nameInConf));
由于在jar包内部获取到的jarUri 为jar:file:/D:/ideaWorkspaces/demo/target/demo-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/hive-common-2.1.1.jar!/
该路径在jar包内部使用 new File(jarUri)构建File对象时,会执行到如下语句抛出异常
if (uri.isOpaque())
throw new IllegalArgumentException("URI is not hierarchical");
其中isOpaque()方法的文档中描述:
Tells whether or not this URI is opaque.
A URI is opaque if, and only if, it is absolute and its scheme-specific part does not begin with a slash character ('/'). An opaque URI has a scheme, a scheme-specific part, and possibly a fragment; all other components are undefined.
此处的jarUri的scheme-specific部分是file开头的而不是/开头的所以判断是opaque,故抛出了异常,而此处没有对该异常进行捕获处理,从而导致HiveConf初始化失败
URL result = checkConfigFile(new File(new File(jarUri).getParentFile(), nameInConf));
因此,修改此处源码,加上异常处理可以解决该初始化问题,修改代码可以参考该patch:https://issues.apache.org/jira/browse/HIVE-23700
源码下载路径:Index of /dist/hive/hive-2.1.1
修改源码后可以重新编译该模块:mvn package -pl org.apache.hive:hive-common-patch -am -DskipTests ,使用新编译的hive-common-patch-2.1.1.jar可以解决HiveConf初始化失败问题