利用google app engine开发一个定时器应用

来源:互联网 发布:移动大数据公司有哪些 编辑:程序博客网 时间:2024/05/16 01:53

最近对Google App Engine感兴趣。GAE是免费的(当然也有升级收费的),默认可以建立10个免费的web应用(不过我的账号可以建立25个免费应用^__^),至于配置,如果只是做简单的应用足够应付了,例如做一个定时抓取数据的应用,又或者用goagent搭建梯子。虽然GAE这么好的产品无法在国内(appspot.com在国内是无法访问的),但利用免费的资源做一些简单的事情还是很有意义的,对于如定时抓取数据,针对海外用户数据分析等等就非常有用了。

今天就写一篇关于google app engine定时器的文章。做这个定时器的前提是,假设你已经搭建好了google app engine的开发环境,使用Java语言版本。

google app engine关于定时任务的开发文档说的比较清楚,定时方式设置也比较多样。但最高频率只能到1分钟。如果做一个秒级别的定时器就没法完成,例如每个10秒执行一次,那就不能用scheduled tasks。这是可以使用scheduled tasks与task queue结合。当然也有另外的方式,使用Background threads(后台线程),通过while(true)+sleep(10000)的方式实现定时,但目前不探讨这种方式。

如果说scheduled tasks是用来定时执行任务的可以很好理解。task queue就是任务列队,就不大好理解。字面的理解就是等待执行的任务,默认是1秒可以执行5个任务。但是以什么方式执行呢?

我一开始以为,如果设置60秒执行5次任务,把任务添加到Queue中去,是不是就可以每隔10秒执行一次任务呢?然而这种理解是错误的。即使这样设置,task queue还是会在一瞬间执行列队里的任务,而不是间隔执行。

web应用都是请求方式执行的,而每个task queue就是包含一个请求的路径。每个task queue都是通过执行请求的方式执行任务,每个task queue又可以指定延时时间执行。

这样通过定时任务scheduled tasks每隔1分钟执行一个任务,scheduled tasks也是通过请求执行定时任务的。定义10秒执行一次任务,就是在scheduled tasks里的代码里,添加5个task queue,而每个scheduled tasks之间设置10秒的延时,这样60秒后执行所有的task queue,然后有重新运行下一个scheduled tasks的循环。

好了,下面是实现的代码过程。

1.新建一个Timer的google app engine项目

为了简单起见,新建项目时,将Google SDKs的默认勾选的选项Use Google Web Toolkit去掉。
这样默认生成的项目里,有一个TimerServlet.java的类。我们将这个默认的路径作为定时器的入口。定时器执行任务就会里面的代码。采用的的GET的请求方式。

2.配置cron.xml

如何让定时器执行TimerServlet的任务?这需要添加一个cron.xml的配置文件。里面的可以执行的路径,也可以添加多个任务。目前只添加一个执行任务,没隔一分钟执行一次timer的请求。在WEB-INFO目录下添加cron.xml文件。

cron.xml的文件内容:

view plaincopy to clipboardprint?
  1. <!--?xml version="1.0" encoding="UTF-8"?-->  
  2. <cronentries>  
  3.     <cron>  
  4.         <url>/timer</url>  
  5.         <description>timer every 1 minutes</description>  
  6.         <schedule>every 1 minutes</schedule>  
  7.     </cron>  
  8. </cronentries>  

 这样就可以实现每隔一分钟执行一次TimerServlet的内容了。

3.添加task queue

以上定时任务只是每分钟执行一次。现在让任务执行每隔一分钟的时间间隔里执行5个task queue任务,而每个task queue之间延时10秒,这样就可以实现每隔10秒的定时运行任务了。

修改TimerServlet.java的源码后

view plaincopy to clipboardprint?
  1. package com.timer.main;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.http.*;  
  6.   
  7. import com.google.appengine.api.taskqueue.Queue;  
  8. import com.google.appengine.api.taskqueue.QueueFactory;  
  9. import com.google.appengine.api.taskqueue.TaskOptions;  
  10. import com.google.appengine.api.taskqueue.TaskOptions.Method;  
  11.   
  12. @SuppressWarnings("serial")  
  13. public class TimerServlet extends HttpServlet {  
  14.     public void doGet(HttpServletRequest req, HttpServletResponse resp)  
  15.             throws IOException {  
  16.         resp.setContentType("text/plain");  
  17.         resp.getWriter().println("Timer running");  
  18.         Queue queue = QueueFactory.getDefaultQueue();  
  19.         for(int i=0;i<5;i++){  
  20.         queue.add(TaskOptions.Builder.withUrl("/task").param("key","间隔:"+10*i).method(Method.GET).etaMillis(System.currentTimeMillis()+10000*i));  
  21.         }  
  22.           
  23.     }  
  24. }  

以上代码就是添加了5个task queue,每个任务之间延时10秒,每个任务的请求路径是/task,每次请求的参数通过key传值,请求的方式是GET。

或许你会疑问:
(1).不是需要添加配置文件queue.xml吗?
因为是采取了默认的方式,所以不需要添加queue.xml。

(2).task是什么路径?
task就是下面要写的的TaskServlet.java类。

4.添加TaskServlet.java类

TaskServlet.java类就是task请求的路径,里面的内容才是真正要执行的的具体任务。目前这里只是实现一个打印获取timer传递过来的参数的代码的功能。

TaskServlet.java源码

view plaincopy to clipboardprint?
  1. package com.timer.main;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Date;  
  5.   
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.http.HttpServlet;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10.   
  11. public class TaskServlet extends HttpServlet{  
  12.       
  13.     /** 
  14.      *  
  15.      */  
  16.     private static final long serialVersionUID = 1L;  
  17.   
  18.     @Override  
  19.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
  20.             throws ServletException, IOException {  
  21.         // TODO Auto-generated method stub  
  22.         resp.setContentType("text/plain");  
  23.         resp.getWriter().println("Task running");  
  24.         String key = req.getParameter("key");  
  25. //      resp.getWriter().println(new Date()+":key=="+key);  
  26.         System.out.println(new Date()+":key=="+key);  
  27.     }  
  28.   
  29. }  

为TaskServlet添加url映射,在WEB-INFO/web.xml,添加以下内容:

view plaincopy to clipboardprint?
  1. <!-- http task  -->  
  2.         <servlet>  
  3.         <servlet-name>Task</servlet-name>  
  4.         <servlet-class>com.timer.main.TaskServlet</servlet-class>  
  5.     </servlet>  
  6.     <servlet-mapping>  
  7.         <servlet-name>Task</servlet-name>  
  8.         <url-pattern>/task</url-pattern>  
  9.     </servlet-mapping>  
  10.       
  11.     <!-- Permission -->  
  12.      <security-constraint>  
  13.         <web-resource-collection>  
  14.             <web-resource-name>task</web-resource-name>  
  15.             <url-pattern>/task/*</url-pattern>  
  16.         </web-resource-collection>  
  17.         <auth-constraint>  
  18.             <role-name>admin</role-name>  
  19.         </auth-constraint>  
  20.     </security-constraint>  

如果定时器为了安全起见,可以设置禁止外部用户访问,添加了对task和timer的任务的资源限制请求。
定时器之类的程序一般只允许内部程序访问,所以需要设置管理员权限,目前为了测试,只对task进行设置权限。
只允许管理员访问,可以设置

view plaincopy to clipboardprint?
  1. <security-constraint>  
  2.        <web-resource-collection>  
  3.            <web-resource-name>task</web-resource-name>  
  4.            <url-pattern>/task/*</url-pattern>  
  5.        </web-resource-collection>  
  6.        <auth-constraint>  
  7.            <role-name>admin</role-name>  
  8.        </auth-constraint>  
  9.    </security-constraint>  

如果允许所有人访问,可以设置

view plaincopy to clipboardprint?
  1. <security-constraint>  
  2.        <web-resource-collection>  
  3.            <web-resource-name>task</web-resource-name>  
  4.            <url-pattern>/task/*</url-pattern>  
  5.        </web-resource-collection>  
  6.        <auth-constraint>  
  7.            <role-name>*</role-name>  
  8.        </auth-constraint>  
  9.    </security-constraint>  

好了,目前项目可以完成了。

点击项目,运行Run As ->Web Application

在浏览器输入localhost:8888/timer
每次刷新timer请求,task queue会执行5个时隔10秒的任务请求如图-1。将应用发布到Google App Engine就可以执行每隔10秒的任务了。

timer

最后提供一份源码下载(为了方便网络传输,目前已将项目里lib的jar文件全部去除,如果要正常使用,需要添加相关的Google App Engine jar包,新建一个项目就有相应的jar)

Timer.zip

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 液相色谱两峰分不开怎么办 液相色谱柱老堵怎么办? 没有装usb驱动怎么办 ipad速度越来越慢怎么办 美萍管理软件打不开怎么办 小米4开机黑屏怎么办 小米电脑死机了怎么办 小米8手机死机怎么办 oppa7开不了机怎么办 oppo手机wlan打不开怎么办 三星s6进水黑屏怎么办 银行卡不支持快捷支付怎么办 路由器忘记管理员密码怎么办 云付没有推荐人怎么办 牛呗审核不通过怎么办 华硕笔记本很卡怎么办 淘宝换货没有货怎么办 用手机怎么办网银 手机销号支付宝怎么办 黑狗狗毛发红怎么办 裤子洗掉色了怎么办 没买快递收到怎么办 淘宝介入卖家不举证怎么办 买家拒收快递货怎么办 买家到付拒收怎么办 买家发顺丰到付又拒收怎么办 到付快递骗局怎么办 一年级学生上课走神怎么办 网购出现质量问题怎么办 小米分期没额度怎么办 小米预约错了怎么办 小米商城缺货要怎么办 LG显示器不满屏怎么办 网页页面放大了怎么办 JSP样式失效了怎么办? 客户故意不结账怎么办 面对刁难的顾客怎么办 万家乐燃气灶具不好打火怎么办 垃圾处理器堵了怎么办 银赫入伍金俊秀怎么办 孕妇被蜈蚣咬了怎么办