a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 116|回复: 1

[JAVA] JAVA基础知识:如何使用脚本语言javax.script探秘

[复制链接]
发表于 2012-7-31 22:04:26 | 显示全部楼层 |阅读模式
1、可用的脚本引擎9 q& V) @) [$ j1 e
  Java 6提供对执行脚本语言的支持,这个支持来自于JSR223规范,对应的包是javax.script。默认情况下,Java 6只支持javascript脚本,它底层的实现是Mozilla Rhino,它是个纯Java的javascript实现。可以通过下面的代码列出当前环境中支持的脚本引擎:
* T' M* e- i, ]. P  1.ScriptEngineManager manager = new ScriptEngineManager();. L. D0 u% l3 g  @! y- c# ~. L
  2.        ListScriptEngineFactory> factories = manager.getEngineFactories();
. r2 i. q  w! q( s  3.        for (ScriptEngineFactory f : factories) {
9 [) r& w& ]4 F" [, d  4.            System.out.println(
/ |  h& K( f- J5 ?) E. D+ d  5.                    "egine name:"+f.getEngineName()+0 u& ^9 J: U! t6 t, w# S
  6.                    ",engine version:"+f.getEngineVersion()+% t8 @; g. Q' E# u% ]2 d
  7.                    ",language name:"+f.getLanguageName()+5 f5 P8 |7 b: n1 k- }, R4 m. \
  8.                    ",language version:"+f.getLanguageVersion()+( d  k+ L9 ?& ?7 p) X6 R( L
  9.                    ",names:"+f.getNames()+8 z8 x. m) _( a0 g6 X4 H
  10.                    ",mime:"+f.getMimeTypes()+; G' Y- K9 C) ~  {+ \  b6 f
  11.                    ",extension:"+f.getExtensions());
$ t' \% a, }+ ^: \/ d/ I5 _& a" A  12.        }
3 H$ ?& [9 B5 `  输出结果:egine name:Mozilla Rhino,engine version:1.6 release 2,language name:ECMAScript,language version:1.6,names:[js, rhino, javascript, javascript, ECMAScript, ecmascript],mime:[application/javascript, application/ecmascript, text/javascript, text/ecmascript],extension:[js]。9 {0 R9 w% i5 G6 ?
  可以看到,Java内置只支持javascript一种脚本。但是,只要遵循 JSR223,便可以扩展支持多种脚本语言,可以从https://scripting.dev.java.net/上查找当前已被支持的脚本的第三方库。! G" d) l/ G* B# V4 L2 q
  2、hello script
# P# W0 G- p# I( m  接下来给出在Java中使用javascript的Hello world示例:- l2 A4 }! }4 s2 |0 H
  13.ScriptEngineManager manager = new ScriptEngineManager ();
& @3 t/ A3 _2 T  14.        ScriptEngine engine = manager.getEngineByName ("js");  F( W+ U; H" U* z! @, F/ W6 o5 F
  15.        String script = "print ('hello script')";
9 d9 l6 t. |6 C+ c# }* O  16.        try {
( @4 Y% B5 B2 m2 z$ I# [  17.            engine.eval (script);
. N$ B8 i8 {% R8 T& o' `" x  18.        } catch (ScriptException e) {; B' F; E# `; J. o8 R
  19.            e.printStackTrace();
  z. v  _6 i+ q  i% R3 ^  20.        }8 Q4 K/ C$ A0 y' l( @8 q. c& E
  使用的API还是很简单的,ScriptEngineManager是ScriptEngine的工厂,实例化该工厂的时候会加载可用的所有脚本引擎。从工厂中创建ScriptEngine可以使用getEngineByName、getEngineByExtension或 getEngineByMimeType来得到,只要参数名字能对上。执行脚本调用eval方法即可(效果等同于javascript中的eval)。
4 G7 {9 A* O2 d' N9 @; t& M% g7 y$ N  3、传递变量
0 ~% t' E7 ~1 m* |# y% D8 |  可以向脚本中传递变量,使得Java代码可以和脚本代码交互,示例如下:
. O4 j0 u2 P- F  21.ScriptEngineManager manager = new ScriptEngineManager();0 r6 C4 y2 ?8 I* E( H- C
  22.        ScriptEngine engine = manager.getEngineByName("js");
, m* R5 Q( K8 @7 H9 C  23.        engine.put("a", 4);
( G) W0 s6 s) G4 h6 |  24.        engine.put("b", 6);- T. W4 U7 c+ b- \0 b9 E
  25.        try {& u% R( L. P$ S& S* [& g
  26.            Object maxNum = engine.eval("function max_num(a,b){return (a>b)?a:b;}max_num(a,b);");% ~2 k7 v' {7 L3 N4 y
  27.            System.out.println("max_num:" + maxNum);3 n& f# N# c8 x
  28.        } catch (Exception e) {3 _5 f) L( ]* y9 J
  29.            e.printStackTrace();$ U+ {* _( _8 L& V# i0 n
  30.        }
2 q3 F6 y8 ]. ]  输出内容:max_num:69 A" f8 I3 S7 {1 F( a" J$ f
  对于上面put的变量,它作用于自身engine范围内,也就是ScriptContext.ENGINE_SCOPE,put 的变量放到一个叫Bindings的Map中,可以通过 engine.getBindings(ScriptContext.ENGINE_SCOPE).get(“a”);得到put的内容。和 ENGINE_SCOPE相对,还有个ScriptContext.GLOBAL_SCOPE 作用域,其作用的变量是由同一ScriptEngineFactory创建的所有ScriptEngine共享的全局作用域。
) [, N$ a( i8 L  4、动态调用! }/ |) a: n/ @
  上面的例子中定义了一个javascript函数max_num,可以通过Invocable接口来多次调用脚本库中的函数,Invocable接口是 ScriptEngine可选实现的接口。下面是个使用示例:
% c4 o- `$ v$ h8 U6 U2 X; r+ B  31.ScriptEngineManager manager = new ScriptEngineManager();6 n3 W$ ]! z& i* M$ U! _
  32.        ScriptEngine engine = manager.getEngineByName("js");
3 f, C* @# _) G* s: }  33.        try {
+ ~& e* ]' |  y& m5 M  34.            engine.eval("function max_num(a,b){return (a>b)?a:b;}");
回复

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:27 | 显示全部楼层

JAVA基础知识:如何使用脚本语言javax.script探秘

 35.            Invocable invoke = (Invocable) engine;2 @0 t8 W$ {7 j  `: d1 x
  36.            Object maxNum = invoke.invokeFunction("max_num",4,6);
* ~7 e* ?4 a5 S' t# U3 r  37.            System.out.println(maxNum);/ W: s3 B4 I2 g! z: _" h0 n) E
  38.            maxNum = invoke.invokeFunction("max_num", 7,6);
5 m/ G. a, d) v; g  39.            System.out.println(maxNum);9 k/ G9 u6 e: {8 }, M4 C
  40.        } catch (Exception e) {
( m  y( M1 b$ m2 T: L  41.            // TODO: handle exception+ i: L: C: D1 w
  42.        }  r2 Z- \7 I/ v8 S4 n0 ~( Q
  上面的invokeFunction,第一个参数调用的脚本函数名,后面跟的可变参数是对应的脚本函数参数。
! j) G; s3 O" g5 P+ J0 P  Invocable还有个很酷的功能,就是动态实现接口,它可以从脚本引擎中得到Java Interface 的实例;也就是说,可以定义个一个Java接口,其实现是由脚本完成。以上面的例子为例,定义接口JSLib,该接口中的函数和javascript中的函数签名保持一致:
# }( a1 P5 Y0 o; v; e, L/ F  1.public interface JSLib {, N" T. F1 Y- y; M; }1 W" ?# ]
  2.       public int max_num(int a,int b);/ P& v$ S) S5 D8 I2 h) b
  3.   }
3 ^0 S) C: F: u4 [/ I' @  调用示例:5 D% r" x) e) H& h  ~
  4.ScriptEngineManager manager = new ScriptEngineManager();# h3 ?9 j. l- l9 a  g2 l. j
  5.        ScriptEngine engine = manager.getEngineByName("js");, W% i* d0 q2 Z; Z
  6.        try {
6 p- k- ?* R" f" Y" x. V  7.            engine.eval("function max_num(a,b){return (a>b)?a:b;}");7 k9 X: y1 Y  v  k: ~
  8.            Invocable invoke = (Invocable) engine;
6 w, |) ]. w5 V% f$ a! Z& ?# v& \  h  9.            JSLib jslib = invoke.getInterface(JSLib.class);: |1 s2 |0 c2 T1 Z/ o
  10.            int maxNum = jslib.max_num(4,6);
3 u4 l; O- I( o. y( z$ w  11.            System.out.println(maxNum);
4 e! h# D* g- e. \7 ]( x0 ^" ^" W( c  12.        } catch (Exception e) {
/ k+ o# q. s* V9 e( [  13.            // TODO: handle exception
: Q6 e( \, o$ H, u! u) B  14.        }, D. \: ]  p# ?( d% ?
  5、使用Java对象
" L+ D- |& K! b+ _0 |" [+ k  可以在javascript中使用Java代码,这确实是很酷的事情。在Rhino中,可以通过importClass导入一个类,也可以通过importPackage导入一个包,也可以直接使用全路经的类。在创建对象时,new也不是必须的。示例代码如下:
7 |7 a7 w, U: |3 b( ]7 p  15.ScriptEngineManager manager = new ScriptEngineManager();
+ \& z' x9 Z) }7 F  16.        ScriptEngine engine = manager.getEngineByName("js");+ m9 D! d" m3 l' {$ a$ Y
  17.        try {
; \8 A7 Z6 h7 \  18.            String script = "var list = java.util.ArrayList();list.add(\"kafka0102\");print(list.get(0));";4 }' v# V5 ]+ h+ a; {" {- u
  19.            engine.eval(script);
# h3 e8 Y6 W0 Y7 J) V" ]  20.        } catch (Exception e) {
/ G+ [1 m' I5 B' Z' H# @3 B# U  21.            e.printStackTrace();/ V; E' A9 u2 B7 f- V1 b
  22.        }, V9 |, l* n  }3 P) X. W4 F
  6、编译执行
$ ?& q0 R- Y- c  脚本引擎默认是解释执行的,如果需要反复执行脚本,可以使用它的可选接口Compilable来编译执行脚本,以获得更好的性能,示例代码如下:
) M5 u( q, W$ x9 `* Z; f5 P  23.ScriptEngineManager manager = new ScriptEngineManager();0 j: ]6 C6 i3 s9 \
  24.        ScriptEngine engine = manager.getEngineByName("js");
0 G4 y' l7 A3 U, r% o# P  25.        try {" @: `6 e! @$ t8 S
  26.            Compilable compEngine = (Compilable) engine;
6 D& b: e: V5 {! K. V  27.            CompiledScript script = compEngine.compile("function max_num(a,b){return (a>b)?a:b;}");4 I3 Q! n1 Z( P+ F
  28.            script.eval();
" Y4 p4 U6 ~6 r  29.            Invocable invoke = (Invocable) engine;
' Q" a6 {  }5 q- R$ u" C5 E; Y2 y/ x  30.            Object maxNum = invoke.invokeFunction("max_num",4,6);& R. G: v  H0 t3 H- n0 l
  31.            System.out.println(maxNum);$ ^/ B2 d/ O- i! `; F/ L# E
  32.        } catch (Exception e) {
2 p) Z( q& I1 R4 N  33.            e.printStackTrace();. y1 E0 }" m0 B/ l( e7 y
  34.        }
% W4 L$ @; G. q- m  7、总结- ^: f  m0 E( r, \: B; L9 C3 S6 t$ u
  除了上面提到的特性,脚本引擎还有一些不错的功能,比如可以执行脚本文件,可以由多线程异步执行脚本等功能。引入脚本引擎,可以对一些配置扩展和业务规则做更强大而灵活的支持,也方便使用者选择自己熟悉的脚本语言来编写业务规则等
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-3 01:37 , Processed in 0.207652 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表