Kotlin 丢失了一些 JRE 类
在服务器上部署嵌入式 Tocmat 时, 发现了 java.lang.NoClassDefFoundError
异常 org.ietf.jgss.GSSException
:
Exception in thread "main" java.lang.NoClassDefFoundError: org/ietf/jgss/GSSException
at org.apache.catalina.startup.Tomcat.initSimpleAuth(Tomcat.java:602)
at org.apache.catalina.startup.Tomcat.getEngine(Tomcat.java:473)
at org.apache.catalina.startup.Tomcat.getHost(Tomcat.java:444)
at org.apache.catalina.startup.Tomcat.addContext(Tomcat.java:240)
at develon.java.EmbeddedTomcat.init(EmbeddedTomcat.kt:38)
at develon.java.EmbeddedTomcatKt.main(EmbeddedTomcat.kt:76)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.jetbrains.kotlin.runner.AbstractRunner.run(runners.kt:61)
at org.jetbrains.kotlin.runner.Main.run(Main.kt:110)
at org.jetbrains.kotlin.runner.Main.main(Main.kt:120)
Caused by: java.lang.ClassNotFoundException: org.ietf.jgss.GSSException
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 13 more
经过 locate 排查, 发现 Kotlin 似乎是完全有自己的一副运行时类库, 所以还是存在一定程度的不兼容
/snap/kotlin/38/lib/kotlin-reflect-sources.jar
/snap/kotlin/38/lib/kotlin-reflect.jar
/snap/kotlin/38/lib/kotlin-runner.jar
/snap/kotlin/38/lib/kotlin-script-runtime-sources.jar
/snap/kotlin/38/lib/kotlin-script-runtime.jar
/snap/kotlin/38/lib/kotlin-scripting-common.jar
/snap/kotlin/38/lib/kotlin-scripting-compiler-impl.jar
/snap/kotlin/38/lib/kotlin-scripting-compiler.jar
/snap/kotlin/38/lib/kotlin-scripting-jvm.jar
/snap/kotlin/38/lib/kotlin-source-sections-compiler-plugin.jar
/snap/kotlin/38/lib/kotlin-stdlib-jdk7-sources.jar
/snap/kotlin/38/lib/kotlin-stdlib-jdk7.jar
/snap/kotlin/38/lib/kotlin-stdlib-jdk8-sources.jar
/snap/kotlin/38/lib/kotlin-stdlib-jdk8.jar
/snap/kotlin/38/lib/kotlin-stdlib-js-sources.jar
/snap/kotlin/38/lib/kotlin-stdlib-js.jar
/snap/kotlin/38/lib/kotlin-stdlib-sources.jar
/snap/kotlin/38/lib/kotlin-stdlib.jar
那只好用 Java 运行了, Kotlin 的基本类库都是哪些呢?
kotlin-stdlib.jar
kotlin-reflect.jar
kotlin-script-runtime.jar
在我的 Ubuntu 上
/snap/kotlin/38/lib/kotlin-stdlib.jar
/snap/kotlin/38/lib/kotlin-reflect.jar
这些就足以令我的 Tomcat 跑起来了
root@iZfi4626828hfcZ:~/Kotlin# java -cp 'nginx.jar:tomcat-embed-core-7.0.52.jar:tomcat-embed-logging-juli-7.0.52.jar:tomcat-annotations-api-7.0.52.jar:/snap/kotlin/38/lib/kotlin-reflect.jar:/snap/kotlin/38/lib/kotlin-stdlib.jar' develon.java.EmbeddedTomcatKt
请输入主目录
工作目录: /root/Kotlin/.
启用 Spring
Sep 29, 2019 8:00:06 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-80"]
Sep 29, 2019 8:00:07 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Sep 29, 2019 8:00:07 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.52
开始注射 DispatcherServlet -> STARTING_PREP
注射失败: org/springframework/web/servlet/support/AbstractAnnotationConfigDispatcherServletInitializer
Sep 29, 2019 8:00:07 PM org.apache.catalina.loader.WebappLoader buildClassPath
INFO: Unknown loader jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f class jdk.internal.loader.ClassLoaders$AppClassLoader
开始注射 DispatcherServlet -> STARTING_PREP
注射失败: org/springframework/web/servlet/support/AbstractAnnotationConfigDispatcherServletInitializer
Kotlin 提供了一个符号链接 /snap/kotlin/current, 那我们必须写一个脚本
#!/bin/bash
kotlin='/snap/kotlin/current/lib'
argc="$#"
CLASSPATH='.'
if (($argc<1)); then
echo \
"jk -cp ./target.jar -cp 'tomcat/lib/*spring*.jar' <Class> [参数列表...]
使用Java运行时运行Kotlin编译的类, 添加了Kotlin运行时
通过-cp 'classpath'来附加类路径, 通配符要用单引号''包装起来形成独立的参数
"
exit 0
fi
function startJava() {
CLASSPATH="$CLASSPATH:$kotlin/kotlin-stdlib.jar:$kotlin/kotlin-reflect.jar"
#echo "类加载路径->$CLASSPATH"
#echo "参数数量$#"
#echo "参数->""$@"
java -cp "$CLASSPATH" "$@"
}
i=0
while (($i<$#)); do
let j=i+1
arg=$(eval echo "$""$j")
#echo $arg
if [ "$arg" == "-cp" ]; then
shift 1
addClassPath=$(eval echo "$""$j")
CLASSPATH="$CLASSPATH:${addClassPath// /:}" # 添加类路径, 同时替换空格为':', 方便使用通配符'*'和'?'
else # 这里开始是类名
javaClass="$(eval echo "$""$j")"
#echo "执行类$javaClass"
let k=j+1
toJava=""
while (($k<=$#)); do
toJava="$toJava '$(eval echo "$""$k")'"
#echo "$toJava"
let k++
done
eval startJava '"$javaClass"' $toJava
exit 0
fi
let i++
done
该脚本最新版本请在 Github下载
jk 脚本使用范例:
sudo jk -cp 'nginx.jar:tomcat-embed-core-9.0.24.jar' -cp 'spring/libs/sp*SE.jar' -cp tomcat-annotations-api-9.0.24.jar develon.java.EmbeddedTomcatKt
请输入主目录
工作目录: /home/ubuntu/www/.
启用 Spring
Sep 29, 2019 5:05:40 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-80"]
Sep 29, 2019 5:05:40 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Tomcat]
Sep 29, 2019 5:05:40 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet engine: [Apache Tomcat/9.0.24]
开始注射 DispatcherServlet -> STARTING_PREP
注射完成
Sep 29, 2019 5:05:41 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring DispatcherServlet 'dispatcher'
Sep 29, 2019 5:05:41 PM org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: Initializing Servlet 'dispatcher'
Sep 29, 2019 5:05:42 PM org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: Completed initialization in 1365 ms
Sep 29, 2019 5:05:42 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-80"]
嵌入式tomcat启动完毕!