Objectify和TimerTask:没有为此线程注册API环境 [英] Objectify and TimerTask: No API environment is registered for this thread
问题描述
我试着让一个 TimerTask
设置为定期从Google App Engine的数据存储中删除条目。因此,我使用 Timer
设置了 ServletContextListener
。
在 contextInitialized
中,我注册了Objectify类:
ObjectifyService .register(Person.class);
然而,当任务实际运行时,它会抱怨没有设置API环境: p>
线程Timer-0中的异常java.lang.NullPointerException:此线程没有注册API环境。
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:80)
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:90)
at com.google.appengine.api.datastore.Query。< init>(Query.java:214)
at com.google.appengine.api.datastore.Query。< init>( Query.java:143)
at com.googlecode.objectify.impl.cmd.QueryImpl。< init>(QueryImpl.java:72)
at com.googlecode.objectify.impl.cmd.LoadTypeImpl .createQuery(LoadTypeImpl.java:50)
at com.googlecode.objectify.impl.cmd.LoadTypeImpl.filter(LoadTypeImpl.java:58)
at myApp.MyServletContextListener $ MyTask.run(MyServletContextListener.java :58)
在java.util.TimerThread.mainLoop(Timer.java:555)
在java.util.TimerThread.run(Timer.java:505)
有什么想法?我尝试将注册类的行改为 ObjectifyService.factory()。register(Person.class);
但它似乎没有帮助。
从 java.util.Timer
class 的文档:
与每个Timer对象对应的是单个后台线程。
和 java.util的内部代码,以了解如何使用Java编写的代码。 Timer class ,我们可以看到它基本上通过调用 new Thread()
来实例化线程。
同时,从 App Engine的文档了解有关使用线程的内容他们的Java沙箱:
Yo您必须使用 ThreadManager 上的某种方法来创建您的线程。 您无法自己调用新的Thread()或使用默认的线程工厂。
Timer
对象实例化了它们自己的线程,然后执行Objectify查询,但由于在ThreadManager外部实例化的线程没有为它们设置适当的App Engine API环境,所以它会抛出一个例外。
您需要重构代码以避免使用Timer和TimerTask类,而是使用基本线程。例如,而不是使用:
import java.util.Timer;
import java.util.TimerTask;
...
定时器定时器=新的定时器();
timer.schedule(new TimerTask()
{
@Override
public void run()
{
// Objectify query here。
}
},5000);
您可以使用:
import com.google.appengine.api.ThreadManager;
...
final long tScheduleDelay = 5000;
ThreadManager.createThreadForCurrentRequest(new Runnable()
{
@Override
public void run()
{
try
{
Thread.sleep(tScheduleDelay);
}
catch(InterruptedException ex)
{
//记录可能的异常
}
/ / Objectify query here。
}
}).start();
I'm trying to get a
TimerTask
set up to remove entries from Google App Engine's dataStore periodically. So I set up aServletContextListener
with aTimer
.Inside the
contextInitialized
, I have registered my Objectify classes:ObjectifyService.register(Person.class);
However, when the task actually runs, it complains that no API environment has been set up:
Exception in thread "Timer-0" java.lang.NullPointerException: No API environment is registered for this thread. at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:80) at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:90) at com.google.appengine.api.datastore.Query.<init>(Query.java:214) at com.google.appengine.api.datastore.Query.<init>(Query.java:143) at com.googlecode.objectify.impl.cmd.QueryImpl.<init>(QueryImpl.java:72) at com.googlecode.objectify.impl.cmd.LoadTypeImpl.createQuery(LoadTypeImpl.java:50) at com.googlecode.objectify.impl.cmd.LoadTypeImpl.filter(LoadTypeImpl.java:58) at myApp.MyServletContextListener$MyTask.run(MyServletContextListener.java:58) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)
Any ideas? I've tried changing the line that registers the class to
ObjectifyService.factory().register(Person.class);
but it didn't seem to help.解决方案From the documentation of
java.util.Timer
class:Corresponding to each Timer object is a single background thread.
And peeking to the inner code of the
java.util.Timer
class, we can see that it basically instantiates the thread by invokingnew Thread()
.Meanwhile, from App Engine's documentation about the use of threads in their Java sandbox:
You must use one of the methods on ThreadManager to create your threads. You cannot invoke new Thread() yourself or use the default thread factory.
So what happened here is the
Timer
object instantiated their own thread, which then executes the Objectify queries, but since threads instantiated outside ThreadManager does not have the proper App Engine API environment set up for them, it throws an exception.You need to refactor your code to avoid using the Timer and TimerTask classes and use basic threads instead. For example, instead of using:
import java.util.Timer; import java.util.TimerTask; ... Timer timer = new Timer(); timer.schedule( new TimerTask() { @Override public void run() { // Objectify query here. } }, 5000 );
You could instead use:
import com.google.appengine.api.ThreadManager; ... final long tScheduleDelay = 5000; ThreadManager.createThreadForCurrentRequest( new Runnable() { @Override public void run() { try { Thread.sleep( tScheduleDelay ); } catch ( InterruptedException ex ) { // log possible exception } // Objectify query here. } } ).start();
这篇关于Objectify和TimerTask:没有为此线程注册API环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!