我原来的 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)
答案 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