JSAPI用户手册
本文档主要涵盖如何嵌入SpiderMonkey javascript引擎到你自己的c++程序中。
JavaScript在浏览器端已经被广泛使用了。但是,Mozilla的javascript引擎可以被嵌入到任何c++程序中,而不仅仅是应用于浏览器。许多应用程序开发可以通过脚本化的方式获益,这些程序可以使用SpiderMonkey API让c++代码里面跑js代码。
What SpiderMonkey does?
Javascript引擎编译并执行js脚本。引擎本身负责脚本执行时的对象内存分配,垃圾收集等工作。
SpiderMonkey支持Javascript 1.0-1.8版本。Js 1.3以及后来的版本都符合ECMAScript 262-3规范。后面的版本也包含Mozilla扩展,比如数组压缩(array comprehensions)和生成器(generators).SpiderMonkey也支持E4X,但是这个是可选的。
在Javascript的世界里面,我们马上就可以想到许多特性,比如事件处理(onclick),DOM对象,window.open以及XMLHTTPRequest.但是,在Mozilla里面所有的特性都是由另外的组件提供,而不是SpiderMonkey引擎本身。SpiderMonkey引擎本身只提供javascript核心数据类型,比如number,string,array,object等。还有一些常用的方法,比如Array.push。SpiderMonkey还可以让其它程序非常方便地暴露自己程序中的对象和接口给js代码。比如,浏览器暴露的就是DOM接口。(cocos2d-x暴露的是cocos2d-x的接口)。你自己的程序也可以根据脚本的需求来设计待暴露接口。具体由程序开发者自己来决定哪些对象和方法要暴露给脚本。
Hello World
Using the SpiderMonkey library
你的程序可以像使用任何其它c++程序库一样来使用SpiderMonkey。如果想从源码构建SpiderMonkey,可以参考SpiderMonkey构建文档.你也可以把SpiderMonkey当作一个静态库或者动态库集成进来。
有一些平台上面(比如Debian linux)内置了SpiderMonkey包。这样子安装会变得非常容易,但是调试可能会比较复杂。XULRunner SDK里面也包含一个SpiderMonkey引擎,同时还有头文件和库文件。
c++代码通过JSAPI来访问SpiderMonkey,通过导入头文件”jsapi.h”。JSAPI提供了相应的函数来建立javascript运行时环境,编译,执行脚本,创建和访问javascript数据结构,处理错误,允许安全性检查以及调试脚本。
如果想了解JSAPI的全部能力,你可以查看JSAPI Reference;
The SpiderMonkey universe
如果想在SpiderMonkey里面跑javascript,一个程序必须有三个关键元素:一个JSRutime,一个JSContext和一个全局对象。这一小节专门来阐述这三个关键元素。下一节主要是介绍怎么使用JSAPI来配置这三个关键元素。
Runtimes 一个JSRutime,或者说运行时。你的程序里所有的js变量,对象,脚本和上下文都由它来分配内存。每一个JSContex和每一个js对象都依托于JSRuntime。它们不能越界访问,也不能共享资源。大部分应用程序只需要一个runtime就可以了。
Contexts一个JSContext,或者说上下文。它是一个小的虚拟机,但是可以完成许多javascript对象相关的任务。它负责编译和执行脚本,设置和访问js对象的属性,调用js函数,把js数据类型转换成其它数据类型,创建对象等等。几乎所有的JSAPI都需要一个JSContext 对象作为第一个参数。就像<stdio.h>里面的文件操作一样,都需要一个FILE*指针。
在context和线程之间还有一层亲密关系。简单来说,单线程的程序可以使用一个context就够了。但是,一个context一次只能做一件事情。因此,在一个多线程程序中,一个线程在任何时刻应该可以使用任意给定的context。那样的程序,一般来说会设计成每一个线程拥有自己的context。js对象,从另一个角度来说,它并不是一直与script、thread和创建它的context同生共死的。它们可以被许多脚本或者许多线程所共用。如图1。1所示:
Figure 1.1 js脚本、上下文和对象的关系
Global objects 最后,全局对象包含js脚本中所有的类、函数和变量。脚本里所做的任何操作,比如window.open(“http://www.mozilla.org/”), 它都需要访问全局属性,在此例中就是window。JSAPI应用程序对于全局对象里面应该暴露哪些属性给js脚本拥有绝对的控制权。程序刚开始时会创建一个对象,然后使用js的标准类来操作它,比如Array和Object。然后,它会提供一些应用程序所需要的类,对象和函数,比如:window。每一次应用程序跑js脚本时(通过调用JS_EvaluateScript),它就会提供全局的对象给脚本访问。当脚本在运行的时候,它也可以创建自己的全局函数和全局变量。所以这些函数,类,变量都被当作全局对象的属性。(译注:如果搞过web端的js开发的同学,对这些内容应该不陌生。)
A minimal example
在上一节中描述的三种关键元素需要相应的JSAPI调用:
*The runtime:使用JS_NewRuntime可以创建一个js runtime,对应的可以使用 JS_DestroyRuntime来销毁这个runtime。当你的程序里面集成SpiderMonnkey以后,你可以使用JS_ShutDown来释放掉缓存里面的资源。(虽然说,你的程序退出的时候这些缓存的资源都会被释放,手动调用JS_ShutDown显得有点多此一举。但是,调用它是一个好习惯。)
*The context: 使用JS_NewContext和JS_DestroyContext。为了最大化兼容ECMAScript标准,应用程序需要调用JS_SetOptions来激活JSOPTION_VAROBJFIX.为了支持最新的js语言特性,应用程序需要调用JS_SetVersion。错误报告也是一个context,我们可以用JS_SetErrorReporter来支持它。
*The global object: 为了创建这个对象,你首先需要采用JSCLASS_GLOBAL_FLAGS来创建一个JSClass。下面的例子中,我们举了一个非常简单的JSClass(叫做global_class)。它本身没有任何属性和方法。使用JS_NewGlobalObject来创建一个全局对象。使用JS_InitStandardClasses方法来操作它。
下面的代码向我们展示了一个最简化版的JSAPI应用程序。它包含了我们之前介绍的所有知识点:
1 |
|
每一个JSNative有一样的签名,完全可以忽视Javascript那边所传递的函数参数。
传递给javascript函数的参数由argc和vp.argc来计算,一共传递了多少个参数。然后使用JS_ARGV(cx,cp)来返回这些参数的一个数组。这些参数没有基础c++类型,比如init、float之类的。它们都是一些jsval,即javascript值。这些native的函数使用JS_ConvertArgument来把这些jsval转换成相应的c++类型,然后再把它们存储在本地局部变量中。native函数还使用JS_SET_RVAL(cx,vp,val)来把c++的值返回给js端。
当函数调用成功的时候,一个JSNative必须调用JS_SET_RVAL,并且返回一个JS_TRUE。传递给JS_SET_RVAL的值最终被返回给js端。
当函数调用失败的时候,一个JSNative会调用一个错误处理函数,在本例中就是JS_ReportError,并且返回JS_FALSE。这个代码调用会导致javascript异常被触发。调用者可以在javascript代码里面使用try/catch来捕获这些异常。
要让一个native的函数可以被js端调用,我们需要声明一个JSFunctionSpec表来描述这些函数信息。然后调用JS_DefineFunction。
1 |
|
一旦函数被定义在global中,任何脚本使用global作为全局对象都可以调用它,就像每一个web页面可以调用alert函数一样。在上面的配置中,我们可以使用下面的脚本来跑”Hello World”:
1 |
|
JSAPI Concepts
该部分主要任务是填JSAPI的坑。如果你想使用SpiderMonkey来开发什么程序的话,这必须仔细认真细致完整反复地阅读本节的3个部分内容。
Javascript values
主要的文章:jsval
Javascript是一种动态类型的语言:所有的变量和属性在编译间都是没有类型的。那么,像c、c++这种静态类型语言怎么同js交互呢?JSAPI提供了一种数据类型叫做jsval,它可以代表js里面的任何数据类型。一个jsval可以是一个数字,一个字符串,一个bool值,一个对象的引用(比如Object,Array,Data或者Function),甚至可以是null或者undefined。
对于整形和bool值,jsval自身是包含其值的。在其它情况下,jsval只是一个指针 ,要么指向一个对象或者一个数组 。
1 |
|
JSAPI里面包含了一些宏,可以用来测试jsval的javascriopt数据类型。它们是:
1 |
|
一个jsval指向一个JSObject,jsdouble或者JSString对象。你可以把jsval向下转型成你需要的类型。转换的api接口是JSVAL_TO_OBJECT,JSVAL_TO_DOUBLE和JSVAL_TO_STRING。这些api可以帮助我们在需要特性类型的时候去做相应的数据类型转换。类似的,你也可以把一个JSObjectt,jsdouble或者JSString对象指针转换成一个jsval。通过使用OBJECT_TO_JSVAL,DOUBLE_TO_JSVAL和STRING_TO_JSVAL.
Gabage collection
一旦js脚本跑起来以后,所有的js对象,字符串和变量等数据结构都会分配内存。垃圾收集指的是js引擎会自动检测哪些内存没有被引用,而且也不再可能被再次使用,最终js引擎会自动回收这部分内存。
垃圾收集对于一个JSAPI的程序来讲有两个非常重大的影响。首先,应用程序需要保证js里面的任何值都是可以被GC的。垃圾收集器是会很积极地去搜寻没有被引用的内存的,一旦发现有这样的内存块,它就会释放之。其次,应用程序需要考虑垃圾收集器对程序性能的影响。
Keeping objects live
如果你的JSAPI程序crash了,很可能是由于垃圾收集器发生错误了。你的程序必须确保垃圾收集器可以访问到所有正常使用的js变量。否则,没有被gc引用的内存就会被gc释放掉。因为你的程序下次可能会使用到这些被释放的内存,此时,crash发生了。
我们有许多方法可以保证一个值是可以被gc管理到的:
如果你想一个js value在JSNative调用期间都可以被访问,你可以把它存储到*rval或者一个argv数组中。任何值存储在这两个地方都可以被访问到。如果还想使用更多的argv槽,可以使用JSFunctionSpec.extra.
如果一个定制的对象需要把某些值存储在内存中,只需要把这些值当作此对象的属性存储起来即可。只要这个对象是可以被引用的,那么它的属性就是可以被访问到的。如果这些值不一定要让js代码访问,可以使用保留槽reserved slots。 也可以使用一个JSClass.mark,然后把值存储到private data中。
如果一个函数创建新的对象、字符串和数字,它可以使用JS_EnterLocalRootScope和JS_LeaveLocalRootScope来保证这些值在函数调用期间不被释放。
如果想让一个值永久存在,那么可以它把存储到GC root中。
但是,GC bug还是有可能会发生的。这两个函数,都只有在debug模式下面才能使用,它们对于debug和gc相关的crash非常有帮助。
使用JS_SetGCZeal来激活另外一个垃圾收集器。GC zeal会让GC相关的crash暴露地更多,而且富含更多信息。这个只能用于程序开发和debug阶段,因为这个额外的gc会让js跑得非常慢。
使用JS_DumpHeap来把SpiderMonkey的堆和其它有用的信息dump出来。
你可以参考SpiderMonkey Garbage Collection Tip来了解更多信息。
GC performance
如果经常去做自动垃圾收集,会对你的程序性能造成比较大的影响。有一些程序可以通过增加JSRuntime的初始值大小来减少GC的频率。
不过,最好的技术应该是让程序在空闲的时候去做GC,这种情况下面,它对终端用户的影响最小。默认情况下,js引擎的垃圾收集时机是,它除了自动增长进程空间而别无他法时。这句话的意思是,垃圾收集发生在内存很吃紧的时候,但是,这时候做垃圾收集其实也是最坏的时机。一个应用程序可以通过调用JS_GC和JS_MaybeGC两个函数来触发垃圾收集。JS_GC会强制执行垃圾收集。而JS_MaybeGC会提醒垃圾收集器,您老是不是该收集无用的内存资源啦?
Errors and exceptions
检查一个JSAPI函数的返回值的重要性是无需多言的。因为每一个JSAPI函数都会使用一个JSContext指针作为参数,这有可能会导致函数调用失败。因为系统可能会出现内存耗尽的问题。也有可能js脚本中存在语法错误。还有,脚本中有可能显示throw一个异常。
因为Javascript语言本身支持异常,而c++也支持异常,它两肯定不是一码事。SpiderMonkey本身并没有使用任何c++异常。JSAPI也不会抛出c++异常,当SpiderMonkey去调用一个应用程序回调时,这个回调也绝不会抛出一个c++异常。
Throwing and catching exceptions
我们已经看到一个JSNative函数中如何抛出异常的例子了。只需要简单地调用JS_ReportError,然后使用一个和printf风格的参数列表并且返回JS_FALSE。
1 |
|
这个和js语句throw new Error(“Command failed with exit code” + rc)非常相似。另外,需要注意的是,调用JS_ReportError并不会产生一个c++异常。但是SpiderMonkey的栈在展开时不会把c++函数从栈中移除。SpiderMonkey的做法是,返回一个JS_FALSE或者NULL给应用。
如果想了解更多有关异常抛出和异常处理的例子,可以参考JSAPI Phrasebook.
Error reports
- 这些家伙很懒,这部分文档没有。
Automatic handling of uncaught exceptions
在某些特定情况下面,JS_Compile,JS_Call,JS_Execute和JS_Evaluate函数会自动把异常信息传递给error reporter程序。这些函数在执行的时候,都会事先检查JSContext,看其中是否有异常。如果有,那么它们会继续检查是否还有其它js代码或者js函数在此JSContext中。如果有,那么这些异常可能会被捕捉,这时SpiderMonkey什么也没做只返回JS_FALSE,并且让异常可以被传播。但是,如果js栈上什么都没有的话,那么没有被捕获的异常就会被直接传给error reporter。
最后的结果就是,顶层的应用程序设置一个error reporter,然后再开始调用JSAPI函数。应用程序永远都不需要显式去处理未捕获的异常消息。因为error reporter会自动被调用。应用程序也可以禁用这项功能,通过使用(JSOPTION_DONT_REPORT_UNCAUGHT),但是,如果这样做,你还需要显式地调用JS_IsExceptioinPending, JS_GetPendingException, JS_ReportPendingException和JS_ClearPendingException,调用时机就是在JSAPI函数返回JS_FALSE或者NULL之前。
Uncatchable errors
还有一种方式来让JSNative回调来报出一个错误:
1 |
|
这里的代码和JS_ReportError所做的略微有些不同。
大部分的错误,包括由JS_ReportError所抛出的错误,都可以用javascript语言异常来表示。使用js的一些内置api try/catch/finally。但是,有时候,我们并不想让js端去catch某一个错误,而是想让脚本直接就终止运行。如果在脚本执行期间,我们的系统内存耗尽了,我们就不想让finally那部分代码执行了。因为,脚本总需要一点点内存来执行,而此时我们已经没有内存了。如果一个脚本已经运行很长时间了,我们想杀死它,这时候就不能产生异常,因为那样的话js端的catch会捕捉到这个异常并继续执行下去。
因此,JS_ReportOutOfMemory(cx)函数被不会抛出一个异常,它会产生一个不可被捕捉的错误。
如果SpiderMonkey把内存耗尽了,或者是一个JSAPI回调返回JS_FALSE但是没有附带一个异常,那么我们就把它当作一个不可被捕捉的错误。此时,js代码的栈会展开,同时js代码中的catch和finally也不会被执行。
一个不可被捕捉的错误可以让JSContext状态良好。这样JSContext可以被重用。应用程序也不需要额外的操作来从这些错误中恢复。
下面一段代码向我们演示了如何产生一个不可被捕捉的错误:
1 |
|
More sample code
下面的例子使用JSAPI来实现了一些功能。
注意,最重要的例子还是“A minimal example”一节中的例子。大部分的JSAPI代码样例可以在JSAPI Phrasebook找到。
Defining objects and properties
1 |
|
Definning classes
这一部分内容通过使用JSAPI来定义构造函数,原型对象,原型对象的属性,以及构造函数的属性。
初始化一个类,可以通过定义构造函数,原型和一些预定义的实例属性和类属性。类属性和java中的静态属性有点相似。它们都被定义在对象的构造函数作用域内,这样MyClass.myStaticProp就可以和new MyClass()一起被js端所使用了。
JS_InitClass接收很多参数,但是,最后4个参数是可以传递空的。如果你不想让定义的类有相应的属性的话。
注意,你不需要去调用JS_InitClass来创建一个类的实例,这是一个先有鸡还是先有蛋的问题。你只需要调用JS_InitClass,这样脚本在执行new操作的时候就可以找到相应的构造函数了。这样js端就可以通过运行时从对象的prototype对象(MYClass.prototypea)或者继承的对象中访问相应的属性。一般来讲,如果你想让多个实例共享同样的行为,可以使用JS_InitClass.
1 |
|
Running scripts
1 |
|
Calling functions
1 |
|
JSContext
因为在分配和维护context时存在一定的开销,一个JSAPI程序应该:
- 一次只创建需要个数的context。(简言之,就是按需创建)
- 尽可能保持context存活时间更长,而不是反复地释放并重建。(简言之,就是cache)
如果程序创建多个runtime,你需要清楚哪一个runtime和哪一个context相关联。想了解更多,请参考JS_GetRuntime
使用JS_SetContextPrivate和JS_GetContextPrivate来把应用程序相关的数据与context关联起来。
Initializing built-in and global JS objects
如果想了解SpiderMonkey所有内置的对象,可以参考JS_InitStandardClasses.
应用程序提供的全局对象在很大程度上决定了脚本可以做哪些事情。比如,FireFox浏览器使用它自己的全局对象windows。你可以更改自已应用的全局对象,使用JS_SetGlobalObject
Creating and initializing custom objects
除了引擎内置的对象,你还可以创建、初始化和使用你自己的js对象。特别是在你想使用js引擎来自动化你的程序。定制的js对象可以提供了一些直接的服务,或者说它们充当了你的脚本和程序的接口。比如,一个定制的对象可以提供你程序中所有的网络访问功能,也可以充当你的程序与数据库交互的一个中介者。或者可以把你的程序里面原来采用c或者c++编写的功能代码映射成一种js的面向对象形式。这种内置的对象其实就是你的脚本与程序核心交流的桥梁。你可以从脚本里面传值给程序,也可以从程序里面返回值给脚本。
目前有两种方法让js引擎创建定制的对象:
- 编写一个js脚本来创建对象,它的属性、构造器、函数,然后在运行时把这个对象传给js引擎。
- 在你的程序中嵌入一些代码,这些代码定义了js对象的属性和方法,然后调引擎基于这些代码去创建相应的js对象。这种方法的好处是,你的程序包含了本地方法可以直接操作本地对象。
Creating an object from a script
从脚本中创建对象,原因之一就是你只想让这个定制对象和脚本的生命周期一致。如果你想创建一些对象可以在多个脚本中使用,就应该把这个对象嵌入到应用程序中,而不是写在脚本里面。
注意:你也可以使用脚本来创建持久的对象。
使用脚本来创建定制对象:
定义和设计该对象。它的用途是什么?它有哪些数据成员?它有哪些方法?它需要一个构造函数吗?
编写js代码来定义并创建对象。比如,function myfunc(){var x = newObject()}}。注意,使用js脚本编写的js对象是在js引擎context之外的。如果想了解更多有关对象脚本化的内容,可以参考Client-Side JavaScript Guide 和 Server-side JavaScript Guide.嵌入一个合适的js引擎到你的应用程序中,然后编译并执行这些脚本。你有两个选择:1)每次调用一个函数都使用JS_EvaluateScript和JS_EvaluateUCScript来编译来执行js脚本。2)使用JS_CompileScript或者JS_CompileUCScript来编译脚本,然后可以使用JS_ExecuteScript来重复使用之。这个”UC”版本可以支持unicode脚本。
你使用脚本创建的对象,它的生命周期与脚本本身是一致的。你也可以创建一些对象,它们在脚本执行完成之后,还可以存在。一般情况是,当脚本运行完,这些被脚本创建的对象就被销毁了。在许多情况下面,这正是你的应用程序所期待的行为。但是,也有一些特殊的情况,你可能需要让某些对象可以大多个脚本之间共享。
Custom objects
一个应用程序可以不用JSClass来创建定制对象:
在c/c++端使用你的对象的setter/getter和方法。然后为每一个setter or getter编写一个JSPropertyOp。为每一个方法编写JSNative或者JSFastNative方法。
为你的对象的所有的属性,包括gettter and settter声明JSPropertySpec数组。
为你的定制对象的所有的方法声明JSFunctionSpec数组。
调用JS_NewObject,JS_ContructObject or JS_DefineObject来创建对象。
调用JS_DefineProperties来定义对象属性
调用JS_DefineFunctions来定义对象的方法.
JS_SetProperty也可以用来创建对象的属性。但是它创建的属性没有getter和setter。这些属性只是普通的Javascript属性。
Providing private data for objects
就像context一样,你可以把很多数据与对象进行关联,而不需要显式把这些数据当作对象本身的属性。调用JS_SetPrivate可以为对象建立一个指向私有数据的指针。然后再调用JS_GetPrivate来访问这些私有数据。你的应用程序本身负责创建和管理这些可选的私有数据。
想要为你的私有对象创建私有数据,可以按如下方法进行:
- 把私有数据和一个普通的c指针关联起来。
- 调用JS_SetPrivate,指定对象要与哪个私有数据建立联接。
比如:
1 |
|
为了在后续可以访问这些数据,调用JS_GetPrivate,然后把对象作为参数传进来。这个函数会返回此对象的私有数据指针。
1 |
|
后记:后面的部分比较高级,讲的是unicode,安全性,引擎debug和引擎性能调试的内容,如果想继续了解的读者可以参考下面的链接。
Reference: jsapi_user-guid
JSAPI用户手册的更多相关文章
- 微信JSAPI支付
最近在微信H5页面内集成微信JSAPI支付,遇到不少问题,现将集成步骤及遇到的问题记录如下: 1.官方下载SDK,下载地址:https://pay.weixin.qq.com/wiki/doc/api ...
- Rafy 框架-发布网页版用户手册
前段时间把 Rafy 的用户手册由 CHM 格式转换为了网页格式,而且发布到了 github.io 上,即方便文档的实时更新,也方便大家查看. Rafy 用户手册网页版地址: http://zgynh ...
- C#开发微信门户及应用(40)--使用微信JSAPI实现微信支付功能
在我前面的几篇博客,有介绍了微信支付.微信红包.企业付款等各种和支付相关的操作,不过上面都是基于微信普通API的封装,本篇随笔继续微信支付这一主题,继续介绍基于微信网页JSAPI的方式发起的微信支付功 ...
- 关于IOS调用微信支付jsapi不起作用的解决方法
微信支付时,安卓机调用 jsapi可以支付,IOS就不行,点击立即支付,直接返回原立即支付页面,跟刷新页面差不多,解决方案很简单:两句话而已. 不得不说,微信支付坑太多了,我擦..... <sc ...
- 微信jsApI及微信分享对应在手机浏览器的调用总结。
摘录自别人的博客: 第一篇:微信内置浏览器的JsAPI(WeixinJSBridge续) 之前有写过几篇关于微信内置浏览器(WebView)中特有的Javascript API(Javascript ...
- sqlmap用户手册 | WooYun知识库
sqlmap用户手册 说明:本文为转载,对原文中一些明显的拼写错误进行修正,并标注对自己有用的信息. 原文:http://drops.wooyun.org/tips/143 ============ ...
- 微信JSApi支付~集成到MVC环境后的最后一个坑(网上没有这种解决方案)
返回目录 大叔第一人 之前写了关于微信的坑<微信JSApi支付~坑和如何填坑>,今天将微信的jsapi支付封装到了MVC环境里,当然也出现了一些新的坑,如支付参数应该是Json对象而不是J ...
- 微信JSApi支付~订单号和微信交易号
返回目录 谈谈transactionId和out_trade_no 前一篇微信JSApi支付~坑和如何填坑文章反映不错,所以又写了个后篇,呵呵. 每个第三方在线支付系统中都会有至少两类订单号,其一为支 ...
- 微信JSApi支付~坑和如何填坑
返回目录 微信一直用着不爽,这几天研究它的jsapi支付,即在微信内打开H5页面,完成支付的过程,在这个过程中,你将会遇到各种各样的问题,而大叔将把这些问题的解决方法写一下,希望可以给你带来帮助! 一 ...
随机推荐
- java 抽象类和接口
接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力.他们两者之间对抽象概念 ...
- 在JSP中使用CKEditor网页编辑器
为了在我的一个项目使用CKEditor网页编辑器,我开始了寻找应用之法. 我下载了ckeditor_4.3.3_standard和ckeditor-java-core-3.5.3. 之前的版本和现在版 ...
- Maven 包命令
1.必须选中项目,然后单击Run As,选择Maven build. 2.在配置窗体中的Goals栏填写clean package. 注意:Installed JREs中配置的JREs的位置必须是JD ...
- Hadoop第三天---分布式文件系统HDFS(大数据存储实战)
1.开机启动Hadoop,输入命令: 检查相关进程的启动情况: 2.对Hadoop集群做一个测试: 可以看到新建的test1.txt和test2.txt已经成功地拷贝到节点上(伪分布式只有一个节 ...
- Hadoop的分布模式安装
1.确定集群的结构 IP(主机名) 角色 192.168.1.220(hadoop0) NameNode.JobTracker 192.168.1.221(hadoop1) SecondaryNa ...
- C#获取文件的绝对路径
要在c#中获取路径有好多方法,一般常用的有以下五种: //获取应用程序的当前工作目录. String path1 = System.IO.Directory.GetCurrentDirectory() ...
- android系统的文件夹选择器
aFileChooser: https://github.com/iPaulPro/aFileChooser/issues, 这个是最适合android的文件选择器,看看有无可能改成文件夹选择器. f ...
- tinyxml2简单使用
引入头文件 <span style="font-size:18px;">#include "HelloWorldScene.h" #include ...
- mysql慢查询Slow Query Log和未使用索引(Not Using Indexes)查询配置和使用
mysql的“慢查询”指的是超过了允许的最大查询时间(long_query_time)的sql语句,而“未使用索引”查询顾名思义就是查询语句没有使用到索引的sql语句. 慢查询配置和使用 在msyql ...
- Maven Archetype Plugin
使用Archetype的一般步骤 命令——mvn archetype:generate 输入命令后,Archetype插件会输出一个Archetype列表供用户选择:选择自己想要使用的Archetyp ...