使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx

上传人:b****4 文档编号:3997016 上传时间:2022-11-27 格式:DOCX 页数:12 大小:30.81KB
下载 相关 举报
使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx_第1页
第1页 / 共12页
使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx_第2页
第2页 / 共12页
使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx_第3页
第3页 / 共12页
使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx_第4页
第4页 / 共12页
使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx

《使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx》由会员分享,可在线阅读,更多相关《使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx(12页珍藏版)》请在冰豆网上搜索。

使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx

使用GoogleAppEngine实现基于云计算的小型Java数据服务应用

使用GoogleAppEngine实现基于云计算的小型Java数据服务应用

周鹏,软件工程师,IBM

胡沙,软件工程师,IBM

蔡林,软件工程师,IBM

简介:

 GoogleAppEngine 提供给网站开发人员以极其优惠的起步价格,因而深受关注。

在计算方面,它提供了Python和Java两种运行时框架。

在存储方面,它又提供了基于特有的 BigTable 技术,适用于结构化、半结构化数据存储的云存储服务接口。

最新的适用于非结构化数据的 GoogleStorage 也进入了测试阶段。

因而,完整的云计算解决方案大大的提升了Google在这一领域的领先地位。

GoogleAppEngineforJava是2009年Google推出的云计算服务。

与Amazon的EC2比较起来,GoogleAppEngine提供了一个免费的初级版本,这对于广大的Java网站开发人员来说是很有吸引力。

关于如何开始使用AppEngine,developerWorks上已经提供了 GoogleAppEngineforJava 系列文章,因此本文重点介绍AppEngine上的开发数据应用所需的常见技术。

GoogleAppEngine的数据存储是基于Google特有的BigTable技术,与常见的关系型数据库有所不同,因此使用GoogleAppEngine也有别于常。

考虑到Google提供的免费数据空间对于小型应用来说,还是绰绰有余的(目前是根据API的调用次数或数据查询来统计的,而免费的额度很高,一天的免费查询上限为417,311,168次,免费存储空间有1G),所以还是值得开发人员来花一定的时间来学习掌握的。

使用JDO/JPA实现数据对象持久化

面向数据服务的应用关键在于一致、可靠的数据储存模型,在传统计算模型下,基于关系数据库的数据对象存储与查询一直是主流,而AppEngine则采用基于datastore的数据对象存储与查询模型,来实现分布式架构下海量数据的管理及扩展。

尽管datastore不是一个关系型数据库,但仍具有极强的一致性,使得datastore的接口具有与传统数据库一样的特征,从而在延续传统编程接口规范性和便利性的同时,获得了云端存储的高扩展性。

在AppEngine提供的JavaSDK中包含了JDO和JPA两种对象建模与持久化的API实现。

JDO是一个用于存取某种数据仓库中的对象的标准化API,提供透明的对象存储;JPA通过Javaannotation或XML描述对象-关系表的映射关系(O/RMapping),并将运行的实体对象持久化到数据库中。

JDO与JPA同时作为数据对象持久化API,尽管在关系数据库的支持上功能有所重叠,但针对的领域是不同的,JDO更注重提供通用底层数据格式的存储功能,如文件、XML、关系数据库甚至对象数据库。

因此,本文将重点阐述AppEngine的JDOAPI的使用方法。

设置JDO

(1)拷贝appengine-java-sdk/lib/user/orm/目录中的JAR包到应用程序的war/WEB-INF/lib/目录,并确保appengine-api.jar也在该目录中。

(2)在应用程序的war/WEB-INF/classes/META-INF/目录创建jdoconfig.xml配置文件,其内容如下:

xmlversion="1.0"encoding="utf-8"?

>

xmlns:

xsi="http:

//www.w3.org/2001/XMLSchema-instance"

xsi:

noNamespaceSchemaLocation="

value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>

(3)设置数据读取策略和datastore调用期限。

AppEnginedatastore会复制所有的数据到多个存储位置,用以保证当其中一个出现故障时,datastore能迅速的切换到其他位置并正常的访问数据。

为了保证多个数据节点的一致性,应用程序会使用其中一个位置作为主位置(primarylocation),当主位置的数据更新时,其它位置的数据将被并行地改变。

在许多情况下,短时间内返回一些数据格式比等待返回当前数据更为重要,因此当主位置出现故障时,您可以让datastore从其它位置读取数据(可能数据不是最新的),这时就需要设置读取策略(readpolicy)。

Appengine提供两种策略:

strongconsistency和eventualconsistency,其默认策略是strongconsistency。

strongconsistency表示任何情况下都从主存储位置读取数据,而eventualconsistency则表示当主位置不可用时,可从其它存储位置读取数据。

其相应配置如下:

在默认情况下,对datastore的调用直到调用成功才会返回。

如果调用请求的期限到了,运行环境将会终止此次调用请求。

应用程序可以指定调用期限的具体时间,对于批量更新的请求,如果在提交过程中,限定的时间已到,那么到期之前的更新将会被持久化,而之后的更新将不会发生;对于一个事务处理,如果在事务提交过程中期限已到,那么整个事务将会回滚。

其相应的配置如下:

增强数据类

JDO使用一种后置编译处理的增强步骤来实现数据类与JDO实现之间的关联。

如果您使用Eclipse,GooglePluginforEclipse工具会自动完成这个步骤;如果您使用ApacheAnt,可以使用如下命令对已经编译出来的class文件进行增强处理。

java-cpclasspathcom.google.appengine.tools.enhancer.Enhanceclass-files

需要注意的是,Classpath必须包含appengine-tools-api.jar这个JAR包和所有的数据类文件。

获取PersistenceManager实例

应用程序与JDO进行交互是通过PersistenceManager类来实现的,您可以通过PersistenceManagerFactory来获取该类的实例。

由于PersistenceManagerFactory是根据JDO配置来构造的,较为耗时,因此,一个应用应该共享一个单一的实例。

我们可采用一个简单的单例模式类来对其进行封装,例如:

importjavax.jdo.JDOHelper;

importjavax.jdo.PersistenceManagerFactory;

publicfinalclassPMF{

privatestaticfinalPersistenceManagerFactorypmfInstance=

JDOHelper.getPersistenceManagerFactory("transactions-optional");

privatePMF(){}

publicstaticPersistenceManagerFactoryget(){

returnpmfInstance;

}

}

通过该工厂实例,就可以为每次的datastore访问请求创建PersistenceManager实例了,例如:

importjavax.jdo.PersistenceManager;

importjavax.jdo.PersistenceManagerFactory;

importPMF;

//...

PersistenceManagerpm=PMF.get().getPersistenceManager();

try{

//...dostuffwithpm...

}finally{

pm.close();

}

需要注意的是,在使用完PersistenceManager实例后,您需要调用close()方法,以确保不会在其它地方调用。

基于JDOAPI的CRUD

(1)要将简单数据对象存储到数据存储区中,可以调用PersistenceManager的makePersistent()方法,将实例传递给该方法。

对makePersistent()的调用时同步的,直到保存对象并更新索引后才会返回。

要在JDO中保存多个对象,可以使用makePersistentAll(...)方法。

(2)要获取对象,最简单、直接的方法就是通过键(key),利用PersistenceManager的getObjectById()方法来获取。

更加复杂的查询可通过JDO规范中的JDOQL来完成,例如通过lastName来查询Employee信息的查询可通过以下JDOQL完成。

Queryquery=pm.newQuery("selectfromEmployee"+

"wherelastName==lastNameParam"+

"parametersStringlastNameParam"+

"orderbyhireDatedesc");

Listresults=(List)query.execute("Smith");

(3)要将对象从数据存储区中删除,可以使用PersistenceManager的deletePersistent()方法。

(4)使用JDO更新对象的一种方式是抓取对象,然后在返回该对象的PersistenceManager仍然处于打开状态的情况下对该对象进行修改。

当关闭PersistenceManager时,修改部分会自动保留。

基于YAML描述文件以及bulkloader实现大批量结构化数据导入/导出

大批量数据导入,导出是常见的数据服务操作。

目前,对于AppEngineforJava的数据上传,还不是非常简便,需要以下四个步骤:

RemoteApiSelvlet的web.xml的例子。

(1)即使是AppEngineforJava,在批量数据下载和上传方面,还是依赖于AppEngineforPythonSDK的若干Python脚本,如bulkloader.py或是appcfg.py等等。

因而,用户还是需要安装AppEngineforPythonSDK在开发机上。

(2)在AppEngineforJava的google服务器端,需要部署com.google.apphosting.utils.remorteapi.RemorteApiServlet,该Servlet会与安装在AppEgnineforPythonSDK的开发机交互,来实现数据从开发机到服务器端的数据传输。

下面是一个部署RemoteApiSelvlet的web.xml的例子。

remoteapi

com.google.apphosting.utils.remoteapi.RemoteApiServlet

remoteapi

/remote_api

remoteapi

/remote_api

admin

(3)获取当前的AppEngineforJava服务器所用的数据表的Schema,写成yaml格式。

以下面的命令为例,该命令将所使用的DBschema全部下载到bulkloader.yaml内。

用户可以编辑该描述文件,上传后以实现对DBschema的修改。

appcfg.pycreate_bulkloader_config--filename=bulkloader.yaml

--urlhttp:

//

(4)下面是一个DBSchema的实例,该实例的含义是,数据表名为Person,主键是email,还包含属性name,surname,文件传输格式为CSV。

------------------------------------------------------------

transformers:

-kind:

Person

connector:

CSV

property_map:

-property:

__key__

external_name:

email

export_transform:

transform.key_id_or_name_as_string

-property:

name

external_name:

name

-property:

surname

external_name:

prenom

------------------------------------------------------------

(5)上述步骤完成以后,即可使用appcfg.py来实现数据的上传下载。

如下例所示,是用于包含实际数据的CSV文件。

appcfg.pydownload_data--config_file=bulkloader.yaml

            --filename=

            --kind=Person

   --urlhttp:

//

appcfg.pyupload_data--config_file=bulkloader.yaml

--filename=

--kind=Person

--url

--batch_size=200

--num_threads=5

使用Blobstore实现非结构化数据存储

基于Web的数据应用常会遇到非结构化数据存储的需求,如文件、图片或视频的管理。

Appengine采用BlobstoreAPI来管理这些不易被datastore管理的大尺寸(总配额为2GB)数据对象(Blobs)。

一般来说,应用不会直接创建blobs数据,而是由提交的Web表单或者HTTPPOST请求间接创建的。

Blobs在创建之后能够被删除,但不能被修改。

每一个blob在datastore中都有相对应的记录信息,如创建时间、内容类型。

可通过blobkey来查询相关的记录和属性信息。

Blobstore的具体应用过程如下:

上传Blob

(1)编写上传JSP页面,并且设置blobstoreService.createUploadUrl()作为表单的action。

例如:

"

method="post"enctype="multipart/form-data">

(2)编写BlobHandlerServlet,存储Blobkey。

当用户提交表单并触发Handler被调用时,blob就已被Appengine保存并将相关信息添加datastore。

如果应用程序不想保存blob,应立即删除,避免其成为不能被引用到的孤立数据,浪费应用空间。

Handler的主要处理逻辑如下:

Mapblobs=blobstoreService.getUploadedBlobs(req);

BlobKeyblobKey=blobs.get("myFile");

if(blobKey==null){

res.sendRedirect("/");

}else{

res.sendRedirect("/serve?

blob-key="+blobKey.getKeyString());

}

如果不明确指定上传文件的contenttype,Blobstore将会从文件的后缀名推断出contenttype。

如果contenttype不能确定下来,新创建的blob将被赋予application/octet-stream类型。

下载Blob

获取blobkey,编写DownloadHandlerServlet。

这个Handler必须将blobkey传递给blobstoreService.serve(blobKey,response)函数。

下面的例子中,blobkey是通过URL的参数来传递的。

在实际应用中,DownloadHandler可以以任何您需要的方式获取blobkey。

不过每次从Blobstore读取的数据大小被被限制为1MB。

publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres)

throwsIOException{

BlobKeyblobKey=newBlobKey(req.getParameter("blob-key"));

blobstoreService.serve(blobKey,res);

}

基于JCache提高数据存取性能

高性能、可扩展性是Web应用的普遍设计目标,而采用分布式内存数据缓存,并部署于健壮的数据持久层之上,是实现该目标的可靠方法。

AppEngine也包含了内存缓存服务,并支持JCache缓存接口。

JCache提供一个类似于Map的接口用于缓存数据,并通过键(keys)来存取键值,键和值可以是任何可序列化的数据类型和类。

创建并使用JCacheAPI的示例代码如下:

importjava.util.Collections;

importnet.sf.jsr107.Cache;

importnet.sf.jsr107.CacheException;

importnet.sf.jsr107.CacheManager;

//...

Cachecache;

try{

cache=CacheManager.getInstance()

.getCacheFactory().createCache(Collections.emptyMap());

}catch(CacheExceptione){

//...

}

Stringkey;//...

byte[]value;//...

//Putthevalueintothecache.

cache.put(key,value);

//Getthevaluefromthecache.

value=(byte[])cache.get(key);

使用缓存的一个主要目的是为了提升datastore查询的速度。

如果Web应用中的某些基础数据在整个程序的生命周期中变化不

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1