简体   繁体   English

为什么Scalatra有时会给我FlashMap投放错误?

[英]Why does Scalatra give me a FlashMap casting error sometimes?

When running Scalatra in code reload mode, if I load the page before the scalate engine has reinitialized I get a 500 error. 在代码重新加载模式下运行Scalatra时,如果在重新初始化scalate引擎之前加载页面,则会出现500错误。

If I watch the terminal until it looks like the engine has fully reloaded, it works fine, but I think this happens when I load the page between a) successful compile, and b) the container restart. 如果我看着终端直到看起来引擎完全重新加载,就可以正常工作,但是我认为这是在加载页面之间发生的:a)成功编译,b)容器重启。

This won't correct itself until I change something else and force a new compile and code reload. 在我更改其他内容并强制执行新的编译和代码重新加载之前,这不会自行纠正。

I can't seem to find why this is happening, does anyone have any ideas? 我似乎无法找到原因,有人吗?

Here is how I'm doing code reloading: 这是我执行代码重装的方式:

./sbt "container:start" "~ ;copy-resources;aux-compile"

Here is the error I see: 这是我看到的错误:

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)

This error says that there are 2 instances of the same class, loaded by different class loaders. 此错误表明有2个相同类的实例,由不同的类加载器加载。 This behavior rooted in java: classes from different class loaders are not the same. 这种行为源于java:来自不同类加载器的类是不同的。 Basically equals method for classes is the function of a class name and a class loader. 基本上,类的equals方法是类名称和类加载器的功能。 Classes will not be the same in this case even if they come from the same jar or folder. 即使它们来自相同的jar或文件夹,在这种情况下,类也不相同。

When container reloads code it creates a new class loader, while your session still holds instance of flash map loaded using old class loader. 当容器重新加载代码时,它将创建一个新的类加载器,而您的会话仍保留使用旧类加载器加载的Flash映射实例。 This most likely the cause of the issue. 这很可能是问题的原因。

In Java every class is identified by its fully qualified class name and the class loader that has loaded it , this implies that: 在Java中,每个类都由其完全限定的类名称已加载该类的类加载器标识,这意味着:

ClassLoader1.my.package.MyClass != ClassLoader2.my.package.MyClass

This signifiy that it is not possible to cast an object of class MyClass loaded in ClassLoader1 to type MyClass loaded from ClassLoader2 . 这signifiy,这是不可能的投类的对象MyClass在装载ClassLoader1键入MyClass从加载ClassLoader2 You can find more details on 您可以在以下找到更多详细信息

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

On the other hand, it is not possible to load the same class twice in the same class loader, so you need a new class loader, there is no way around it. 另一方面,不可能在相同的类加载器中两次加载相同的类,因此您需要一个新的类加载器,无法解决。 While I never wrote code that performs class reloading, one can suppose that class reloading means in practice: 虽然我从未编写过执行类重载的代码,但是可以认为类重载实际上是指:

  • create a new class loader 创建一个新的类加载器
  • reload the class 重新上课
  • swap class loaders 交换类装载机

Because of what described above, one needs to be careful when designing classes that are supposed to be reloaded: see http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#designing 由于上述原因,在设计应该重新加载的类时,需要格外小心:请参见http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#designing

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM