一、脚本语言的支持 

    JSR 223中规范了在Java虚拟机上运行的脚本语言与Java程序之间的交互方式。JSR 233是JavaSE6的一部分,在Java表中API中的包是javax.script。目前Java虚拟机支持比较多的脚本语言,比较流行的有JavaScript、Scala、JRuby、Jython和Groovy等。 

1. 脚本引擎 
    Java中执行脚本需要脚本语言对应的脚本引擎,JSR 223定义了脚本引擎的注册和查找机制。JavaSE6中自带了JavaScript语言的脚本引擎,基于Mozilla的Rhino实现,可以通过三种方式查找脚本引擎: 
    ① 通过脚本名称获取:

  1. ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");

② 通过文件扩展名获取:

  1. ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");

③ 通过MIME类型来获取:

  1. ScriptEngine engine = new ScriptEngineManager().getEngineByMimeType("text/javascript");

如下代码,查找注册JavaScript脚本引擎,打印"Hello!",JavaScript脚本中的println是Rhino引擎额外提供的方法。 

  1. public class BasicScripting {
  2. public void greet() throws ScriptException {
  3. ScriptEngineManager manager = new ScriptEngineManager();
  4. ScriptEngine engine = manager.getEngineByName("JavaScript");
  5. //ScriptEngine engine = manager.getEngineByExtension("js");
  6. //ScriptEngine engine = manager.getEngineByMimeType("text/javascript");
  7. if (engine == null) {
  8. throw new RuntimeException("找不到JavaScript语言执行引擎。");
  9. }
  10. engine.eval("println('Hello!');");
  11. }
  12. public static void main(String[] args) {
  13. try {
  14. new BasicScripting().greet();
  15. } catch (ScriptException ex) {
  16. Logger.getLogger(BasicScripting.class.getName()).log(Level.SEVERE, null, ex);
  17. }
  18. }
  19. }

2. 语言绑定 
   脚本语言支持API使用语言绑定对象实现Java语言编写的程序与脚本语言间的数据传递。语言绑定对象实际上就是一个简单的哈希表,用来存放和获取需要共享的数据,其定义的接口为javax.script.Bindings,继承自java.util.Map接口。一个脚本引擎在执行过程中可能会使用多个语言绑定对象,不同语言绑定对象的作用域不同。ScriptEngine类提供out和get方法对脚本引擎中特定作用域的默认语言绑定对象进行操作。 

使用默认的语言绑定对象: 

  1. public void useDefaultBinding() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. engine.put("name", "Alex");
  4. engine.eval("var message = 'Hello, ' + name;");
  5. engine.eval("println(message);");
  6. Object obj = engine.get("message");
  7. System.out.println(obj);
  8. }

亦可以自定义语言绑定对象(如语言绑定对象中包含程序自己独有的数据等情形……): 

  1. public void useCustomBinding() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. Bindings bindings = new SimpleBindings();
  4. bindings.put("hobby", "playing games");
  5. engine.eval("println('I like ' + hobby);", bindings);
  6. }

3. 脚本执行的上下文 
    脚本引擎通过执行过程中的上下文对象获取与脚本执行相关的信息,同时允许程序员通过此对象配置脚本引擎的行为。其上下文对象来自javax.script.ScriptContext接口,类似于J2EE中javax.servlet.ServletContext接口,该接口主要包含3类信息: 

① 输入输出 
    默认情况下,脚本输入输出都是在标准控制台中,可以通过setReader和setWriter方法对输出流进行重定向,可以通过setErrorWriter方法进行错误输出重定向。 

  1. //例:将输出重定向到文件
  2. public void scriptToFile() throws IOException, ScriptException {
  3. ScriptEngine engine = getJavaScriptEngine();
  4. ScriptContext context = engine.getContext();
  5. context.setWriter(new FileWriter("output.txt"));
  6. engine.eval("println('Hello World!');");
  7. }

② 自定义属性 
    上下文中通过setAttribute和getAttribute方法获取和设置属性,类似于ServletContext中设置和获取属性操作。与ServletContext中不同的是,ScriptContext中的属性是有作用域之分的,ScriptContext按不同的顺序在不同的作用域中进行属性查找(类似于JSP中EL表达式属性的作用域)。通过ScriptContext的getScopes可以得到其中所有可用的作用域,其中预定义了两个作用域:常量ScriptContext.ENGINE_SCOPE(当前的脚本引擎)和ScriptContext.GLOBAL_SCOPE(从同一引擎工厂中创建的所有脚本引擎对象)。 

  1. public void scriptContextAttribute() {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
  5. context.setAttribute("name", "Bob", ScriptContext.ENGINE_SCOPE);
  6. context.getAttribute("name"); //值为Bob
  7. }

③ 语言绑定对象 
    语言绑定对象位于ScriptContext中,同样也有作用域之分,范围越小,优先级越高。执行如下代码,输出的name值为Bob。 

  1. public void scriptContextBindings() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. Bindings bindings1 = engine.createBindings();
  5. bindings1.put("name", "Alex");
  6. context.setBindings(bindings1, ScriptContext.GLOBAL_SCOPE);
  7. Bindings bindings2 = engine.createBindings();
  8. bindings2.put("name", "Bob");
  9. context.setBindings(bindings2, ScriptContext.ENGINE_SCOPE);
  10. engine.eval("println(name);");    //Bob
  11. }

也可以通过ScriptContext获取语言绑定对象: 

  1. public void useScriptContextValues() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
  5. bindings.put("name", "Alex");
  6. engine.eval("println(name);");
  7. }

前面说到语言绑定对象存在于上下文环境中,故context中保存的自定义属性其实也是保存于语言绑定对象中的,如2中的语言绑定。 

  1. public void attributeInBindings() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
  5. engine.eval("println(name);");
  6. }

4. 脚本编译 
    脚本语言一般均是解释执行的,相对于编译执行的语言,效率较低一些。当脚本语言需要多次重复执行时,可以先对煎熬本进行编译,避免重复解析,提高效率(注:脚本编译需要脚本引擎支持,实现javax.script.Compilable接口)。JavaSE中自带的JavaScript引擎是支持对脚本进行编译的,编译的脚本用javax.script.CompiledScript来表示。 

  1. public class ScriptCompile extends JsScriptRunner {
  2. //对脚本进行编译
  3. public CompiledScript compile(String scriptText) throws ScriptException {
  4. ScriptEngine engine = getJavaScriptEngine();
  5. if (engine instanceof Compilable) {
  6. CompiledScript script = ((Compilable) engine).compile(scriptText);
  7. return script;
  8. }
  9. return null;
  10. }
  11. //先编译再执行
  12. public void run(String scriptText) throws ScriptException {
  13. CompiledScript script = compile(scriptText);
  14. if (script == null) {
  15. return;
  16. }
  17. for (int i = 0; i < 100; i++) {
  18. script.eval();
  19. }
  20. }
  21. public static void main(String[] args) {
  22. ScriptCompile sc = new ScriptCompile();
  23. try {
  24. sc.run("println('Hello');");
  25. } catch (ScriptException ex) {
  26. Logger.getLogger(ScriptCompile.class.getName()).log(Level.SEVERE, null, ex);
  27. }
  28. }
  29. }

5. 方法调用 
    Java虚拟机支持脚本的意义在于实现函数式的编程,即脚本中最重要的便是方法。一些脚本引擎允许使用者单独调用脚本中的某个方法,支持此操作的脚本引擎可以通过实现javax.script.Invocable接口,支持顶层方法或者某对象中成员方法的调用。使用方法调用时最好先检查脚本引擎是否实现了Invocable接口,JavaSE中的JavaScript引擎已实现了Invocable接口。 

① 在Java中调用脚本中的顶层方法 

  1. public void invokeFunction() throws ScriptException, NoSuchMethodException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. String scriptText = "function greet(name) { println('Hello, ' + name); } ";
  4. engine.eval(scriptText);
  5. Invocable invocable = (Invocable) engine;
  6. invocable.invokeFunction("greet", "Alex");
  7. }

② 调用脚本中某对象的成员方法 

  1. public void invokeMethod() throws ScriptException, NoSuchMethodException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. String scriptText = "var obj = { getGreeting : function(name) { return 'Hello, ' + name; } }; ";
  4. engine.eval(scriptText);
  5. Invocable invocable = (Invocable) engine;
  6. Object scope = engine.get("obj");
  7. Object result = invocable.invokeMethod(scope, "getGreeting", "Alex");   //第一个参数为方法所属对象
  8. System.out.println(result);
  9. }

③ 指定脚本中的方法为Java接口的实现 
    Greet是Java实现的接口,包含一个方法getGreeting,通过Invocable.getInterface()方法指定脚本中的方法为Java接口的实现。 

  1. public void useInterface() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. String scriptText = "function getGreeting(name) { return 'Hello, ' + name; } ";
  4. engine.eval(scriptText);
  5. Invocable invocable = (Invocable) engine;
  6. Greet greet = invocable.getInterface(Greet.class);
  7. System.out.println(greet.getGreeting("Alex"));
  8. }

Java语言的动态性支持的更多相关文章

  1. 《深入理解Java 7核心技术与最佳实践》读书笔记(2) Java语言动态性引言

    Java语言是一种静态类型的编程语言.静态类型的含义是指在编译时进行类型检查.Java源代码中的每个变量的类型都要显式地进行声明.所有变量.方法的参数和方法返回值的类型在程序运行之前就必须是已知的.J ...

  2. [原]Java修炼 之 基础篇(一)Java语言特性

    学习软件开发,首先要选择的就是选择需要采用的编程语言,考虑语言本身的优缺点和实际需求,综合评价之后选择相关的语言进行系统开发.本篇博客开始就从近年来比较流行的Java开始为大家讲起. 背景 1995年 ...

  3. Java语言概述

    1.1 基础知识 ·第一代语言 打孔机--纯机器语言 ·第二代语言 汇编 ·第三代语言 C.Pascal.Fortran面向过程的语言 C++面向过程/面向对象 Java跨平台的纯面向对象的语言 .N ...

  4. Java语言国际化

    事实上,Java语言不可能支持所有国家和语言,如需要获取Java语言所支持的语言和国家,可调用Locale类的getAvailableLocale方法获取,该方法返回一个Locale数组,该数组里包含 ...

  5. java语言与jvm虚拟机简介

    一.java语言 1.1 支持面向对象编程oop 强调支持,因为java同样可以面向过程编程. oop的三大特性是:封装.继承.多态. 封装主要针对成员变量而言,oop的思想要求成员变量均为私有,不应 ...

  6. 第1章 Java语言概述--HelloWorld--环境搭建

    SE学什么 第1章 Java语言概述 第2章 基本语法 第3章 数组 第4章 面向对象编程(上) 第5章 面向对象编程(中) 第6章 面向对象编程(下) 第7章 异常处理 第8章 枚举类&注解 ...

  7. Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar

    Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar 前言 公司有一个调研要做,调研如何将Python语言提供的服务纳入到Spring Clou ...

  8. JDK1.7新特性(3):java语言动态性之脚本语言API

    简要描述:其实在jdk1.6中就引入了支持脚本语言的API.这使得java能够很轻松的调用其他脚本语言.具体API的使用参考下面的代码: package com.rampage.jdk7.chapte ...

  9. Java语言支持的变量类型有哪几种

    Java语言支持的变量类型有: 类变量:独立于方法之外的变量,用 static 修饰. 实例变量:独立于方法之外的变量,不过没有 static 修饰. 局部变量:类的方法中的变量. 实例: publi ...

  10. Java语言支持的变量类型有

    Java语言支持的变量类型有: 类变量:独立于方法之外的变量,用 static 修饰. 实例变量:独立于方法之外的变量,不过没有 static 修饰. 局部变量:类的方法中的变量.

随机推荐

  1. windows server 2008 和 win10 双系统安装 ,bios引导 uefi引导总结(可能只适应于我的品牌的笔记本电脑,仅做记录给自己方便下次装系统)

    之前电脑是装好了这两个系统并且正常开机的,bios引导的,也就是开机的时候出现黑框框,上下两个系统选项的那种. 后来在windows server2008里面不小心把win10的盘符给删了一些文件.. ...

  2. 【YashanDB知识库】调整NUMBER精度,再执行统计信息收集高级包偶现数据库异常退出

    [问题分类]功能使用 [关键字]NUMBER类型精度修改,统计信息收集 [问题描述]存量的表将NUMBER类型的字段精度从小精度调整为大精度时,数据库收集这张业务表的统计信息时,会导致数据库异常退出. ...

  3. git merge 详细操作,看完就懂

    [root@hostname git_test]# git init hint: Using 'master' as the name for the initial branch. This def ...

  4. Openstack-Train( 一)基础环境

    openStack-train 搭建部署 当面对KVM集群的时候,我们对KVM的管理以及宿主机的管理就会遇到很大的难度,例如: 查看每一个宿主机有多少台KVM虚拟机? 查看每一个宿主机资源信息,每一个 ...

  5. 【VMware VCF】使用 VCF Import Tool 将现有 vSphere 环境转换为管理域。

    VMware Cloud Foundation 5.2 发布并引入了一个新的功能,借助 VCF Import Tool 工具可以将现有 vSphere 环境直接转换(Convert)为管理工作负载域或 ...

  6. Spring —— 依赖自动装配

    依赖自动装配   IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配 自动装配方式 按类型(常用) 按名称 按构造方法 不启用自动装配    注意: 自动装配用于引 ...

  7. AtCoder Regular Contest 182(A B C)

    原来第二题比第一题简单吗 A.Chmax Rush! \(\texttt{Diff 1110}\) 给定三个序列 \(S,P,V\),其中 \(S\) 的长度为 \(N\),\(P,V\) 的长度为 ...

  8. WPF下使用FreeRedis操作RedisStream实现简单的消息队列

    Redis Stream简介 Redis Stream是随着5.0版本发布的一种新的Redis数据类型: 高效消费者组:允许多个消费者组从同一数据流的不同部分消费数据,每个消费者组都能独立地处理消息, ...

  9. 国产OS 中标麒麟下 C# 桌面应用开发环境搭建笔记

    1.中标麒麟 7.0 x86 桌面版 默认安装创建用户时,如果没勾选 root 用户使用相同的口令,那么安装完成以后,root 是没有设置口令的,通过 sudo passwd root 输入当前普通用 ...

  10. DBA面试资源合集(含Oracle、MySQL、Redis等)-墨天轮

    如今正值金九银十招聘季,众多企业开放大批岗位等待新力量的注入,各位DBA们,你们是否正在激情备战中? 作为企业数据化进程中十分重要的一环,DBA的职责越来越重要,作为高薪资岗位之一,应聘DBA的竞争也 ...