为什么Scalatra有时会给我一个FlashMap投射错误?

为什么Scalatra有时会给我一个FlashMap投射错误?,scala,scalatra,scalate,Scala,Scalatra,Scalate,在代码重新加载模式下运行Scalatra时,如果在scalate引擎重新初始化之前加载页面,则会出现500错误 如果我观察终端直到它看起来引擎已经完全重新加载,它工作得很好,但是我认为在成功编译和容器重启之间加载页面时会发生这种情况 在我更改其他内容并强制重新编译和重新加载代码之前,这不会自动更正 我似乎不明白为什么会这样,有人有什么想法吗 下面是我如何重新加载代码: ./sbt "container:start" "~ ;copy-resources;aux-compile" 以下是我看到的

在代码重新加载模式下运行Scalatra时,如果在scalate引擎重新初始化之前加载页面,则会出现500错误

如果我观察终端直到它看起来引擎已经完全重新加载,它工作得很好,但是我认为在成功编译和容器重启之间加载页面时会发生这种情况

在我更改其他内容并强制重新编译和重新加载代码之前,这不会自动更正

我似乎不明白为什么会这样,有人有什么想法吗

下面是我如何重新加载代码:

./sbt "container:start" "~ ;copy-resources;aux-compile"
以下是我看到的错误:

HTTP ERROR 500

Problem accessing /. Reason:

    org.scalatra.FlashMap cannot be cast to org.scalatra.FlashMap
Caused by:

java.lang.ClassCastException: org.scalatra.FlashMap cannot be cast to org.scalatra.FlashMap
    at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2$$anonfun$1.apply(flashMap.scala:182)
    at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2$$anonfun$1.apply(flashMap.scala:182)
    at scala.Option.map(Option.scala:145)
    at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2.apply(flashMap.scala:181)
    at org.scalatra.FlashMapSupport$$anonfun$org$scalatra$FlashMapSupport$$getFlash$2.apply(flashMap.scala:180)
    at scala.Option.getOrElse(Option.scala:120)
    at org.scalatra.FlashMapSupport$class.org$scalatra$FlashMapSupport$$getFlash(flashMap.scala:180)
    at org.scalatra.FlashMapSupport$class.flash(flashMap.scala:192)
    at beekeeper.controllers.HomeServlet.flash(HomeServlet.scala:13)
    at org.scalatra.FlashMapSupport$$anonfun$handle$1.apply$mcV$sp(flashMap.scala:137)
    at org.scalatra.FlashMapSupport$$anonfun$handle$1.apply(flashMap.scala:136)
    at org.scalatra.FlashMapSupport$$anonfun$handle$1.apply(flashMap.scala:136)
    at scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)
    at org.scalatra.DynamicScope$class.withRequest(DynamicScope.scala:71)
    at org.scalatra.ScalatraServlet.withRequest(ScalatraServlet.scala:49)
    at org.scalatra.FlashMapSupport$class.handle(flashMap.scala:136)
    at beekeeper.controllers.HomeServlet.handle(HomeServlet.scala:13)
    at org.scalatra.ScalatraServlet.service(ScalatraServlet.scala:54)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:255)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
    at org.eclipse.jetty.server.Server.handle(Server.java:365)
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485)
    at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926)
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988)
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635)
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
    at java.lang.Thread.run(Thread.java:744)

此错误表示同一类有两个实例,由不同的类装入器装入。这种行为源于java:来自不同类加载器的类是不同的。类的基本相等方法是类名和类装入器的函数。在这种情况下,类将不相同,即使它们来自同一个jar或文件夹


当容器重新加载代码时,它会创建一个新的类加载器,而您的会话仍然保存使用旧类加载器加载的flashmap实例。这很可能是问题的原因。

在Java中,每个类都通过其完全限定的类名和加载它的类加载器来标识,这意味着:

ClassLoader1.my.package.MyClass != ClassLoader2.my.package.MyClass
这意味着不可能将ClassLoader1中加载的类MyClass的对象强制转换为ClassLoader2中加载的类型MyClass。你可以找到更多关于

另一方面,不可能在同一个类加载器中加载同一个类两次,因此您需要一个新的类加载器,无法绕过它。虽然我从未编写过执行类重载的代码,但可以假设类重载实际上意味着:

创建一个新的类加载器 重新加载类 交换类装入器
由于上述原因,在设计应该重新加载的类时需要小心:请参见

谢谢您的回答!所以我知道有多个类加载器,但是容器重载不应该丢弃旧的类加载器吗?为什么它会一直保留到第二次重新启动?idk,也许jetty类加载中有一个bug。我怀疑你的类路径中是否有两个库具有相同的FlashMap。当然,旧版本的类不应该保留到第二次重新启动。除非您自己使用一些奇特的类加载,否则我怀疑您除了升级jetty之外还能做什么。很明显,在清除所有旧类之前,您无法向服务器发出请求。如果您没有等待足够长的时间,就会出现您可以看到的不兼容。真正的错误是服务器允许您在重新加载时建立连接。。。