Objectify - 清理会议

时间:2015-04-27 06:30:06

标签: java session session-timeout objectify servlet-listeners

我原来的 HttpSessionListener 代码:

public class SessionListener implements HttpSessionListener {
  @Override
  public void sessionDestroyed(HttpSessionEvent event) {
    final Object user = event.getSession().getAttribute("user");
    if (user != null && user insteaceof User) {
      UserUtils.deleteUser((User) user);
    }
  }
}

和我的 web.xml

<filter>
  <filter-name>ObjectifyFilter</filter-name>
  <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>ObjectifyFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

会话超时事件发生时,它会抛出:

  

警告:问题清理会议   java.lang.IllegalStateException:您尚未启动Objectify上下文。你可能错过了ObjectifyFilter。如果未在http请求的上下文中运行,请参阅ObjectifyService.run()方法。       在com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)       在com.learnkeeper.server.OfyService.ofy(OfyService.java:61)       在com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28)       在com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:36)       at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669)       at org.mortbay.jetty.servlet.AbstractSessionManager $ Session.timeout(AbstractSessionManager.java:926)       在org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285)       at org.mortbay.jetty.servlet.HashSessionManager.access $ 000(HashSessionManager.java:44)       在org.mortbay.jetty.servlet.HashSessionManager $ 2.run(HashSessionManager.java:219)       在java.util.TimerThread.mainLoop(Timer.java:555)       在java.util.TimerThread.run(Timer.java:505)

我试过了(来自这篇文章How to resolve "You have not started an Objectify context" in JUnit?):

public class SessionListener implements HttpSessionListener {
  private Closeable closeable;
  @Override
  public void sessionDestroyed(HttpSessionEvent event) {
    final Object user = event.getSession().getAttribute("user");
    if (user != null && user instanceof User) {
      closeable = OfyService.begin();
      UserUtils.deleteUser((User) user);
      closeable.close();
    }
  }
}

这是我的 OfyService类

class OfyService {
  static {
    // Register all my Entities classes
    ObjectifyService.register(User.class);
    ...
  }

  public static Closeable begin() {
    return ObjectifyService.begin();
  }

  public static ObjectifyFactory factory() {
    return ObjectifyService.factory();
  }

  public static Objectify ofy() {
    return ObjectifyService.ofy();
  }
}

但同样 stacktrace :(

那我错过了什么? THX

修改

跟进@stickfigure

所以我清理了我的项目并重新运行我的用例,现在我得到了这个堆栈跟踪:

  

警告:问题清理会话   java.lang.NullPointerException:没有为此线程注册API环境。       在com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:132)       在com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:148)       在com.google.appengine.api.datastore.Key。(Key.java:96)       在com.google.appengine.api.datastore.Key。(Key.java:78)       在com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:54)       在com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:47)       在com.googlecode.objectify.util.DatastoreUtils.createKey(DatastoreUtils.java:86)       在com.googlecode.objectify.impl.KeyMetadata.getRawKey(KeyMetadata.java:187)       在com.googlecode.objectify.impl.Keys.rawKeyOf(Keys.java:36)       在com.googlecode.objectify.impl.Keys.keyOf(Keys.java:29)       在com.googlecode.objectify.impl.LoaderImpl.entity(LoaderImpl.java:121)       在com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28)       在com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:40)       at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669)       at org.mortbay.jetty.servlet.AbstractSessionManager $ Session.timeout(AbstractSessionManager.java:926)       在org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285)       at org.mortbay.jetty.servlet.HashSessionManager.access $ 000(HashSessionManager.java:44)       在org.mortbay.jetty.servlet.HashSessionManager $ 2.run(HashSessionManager.java:219)       在java.util.TimerThread.mainLoop(Timer.java:555)       在java.util.TimerThread.run(Timer.java:505)

2 个答案:

答案 0 :(得分:1)

我没有看到任何理由为什么代码会失败,尽管它可以写得更优雅:

public class SessionListener implements HttpSessionListener {
  @Override
  public void sessionDestroyed(HttpSessionEvent event) {
    final Object user = event.getSession().getAttribute("user");
    if (user != null && user instanceof User) {
      try (Closable closable = OfyService.begin()) {
        UserUtils.deleteUser((User) user);
    }
  }
}

我的应用程序中有很多这种代码的变体,测试用例中有一些例子 - 实际上,Objectify的所有测试用例都依赖于这种模式。

我希望看到运行此代码时生成的确切堆栈跟踪。如果正确调用begin(),那么获取该堆栈跟踪应该是不可能的。您可以查看ObjectifyService.ofy()中的代码 - 这很简单。仔细检查您部署的代码是您认为已部署的代码。

更新:新的堆栈跟踪完全不同,表示GAE未设置为从该侦听器回调执行API调用。它与Objectify无关;现在这是Google的一个问题。我建议编写一个新问题,重点关注该方面,并使用GAE相关标签对其进行标记。

那就是说,我的一般建议是避免依赖这个回调。除了像这样的技术问题,我不相信它会像GAE这样在分布式环境中一致地执行。如果你想要一个对象到期,就把一个日期戳放在上面并剔除一周以上的任何东西(或任何合理的东西)。

答案 1 :(得分:0)

  

Google App Engine不支持会话侦听器。会话侦听器可以在本地调用,但是为此线程注册了没有API环境。在制作中,听众甚至不会调用。

来源@Ramesh V. https://stackoverflow.com/a/11152125/421563

无论如何thx @stickfigure