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启动完毕!
posted @ 2019-09-29 19:44  develon  阅读(501)  评论(0编辑  收藏  举报