Scripting Java(一):Java中执行脚本

Many implementations of scripting and dynamically typed languages generate Java bytecodes so that programs can be run on the Java Platform, just as are actual Java programs. Implementing a language in this
way (or as a Java interpreter class for the scripting language) provides all the advantages of the Java platform: scripting implementations can take advantage of the Java platform‘s binary portability, security, and high performance bytecode execution.

上面这段话可以很好的回答为什么会有这么多基于Java平台的脚本语言。anyway,今天我们只是来看看怎么在我们的Java代码中执行脚本语言。下面使用两种语言来演示,Groovy 2.4.0Scala 2.11.5

有两种方式可以在Java中执行脚本,

Java SE includes JSR 223: Scripting for the Java Platform API. This is a framework by which Java applications can "host" script engines. The scripting framework supports third-party script engines using the JAR service discovery mechanism. It is possible to drop any JSR-223
compliant script engine in the CLASSPATH and access the same from your Java applications (much like JDBC drivers, JNDI implementations are accessed).

所以我们既可以使用JSR223的API来执行脚本,当然也可以直接使用脚本语言提供的API来执行了。下面分别来看看。

JSR-223

通过ScriptEngineManager#getEngineByName这个API我们可以拿到实现了JSR-223的脚本引擎,那么我们怎么知道传什么参数才能拿到Groovy跟Scala的引擎呢?冲进去看看代码就知道了,

    public ScriptEngine getEngineByName(String shortName) {
        if (shortName == null) throw new NullPointerException();
        //look for registered name first
        Object obj;
        if (null != (obj = nameAssociations.get(shortName))) {
            ScriptEngineFactory spi = (ScriptEngineFactory)obj;
            try {
                ScriptEngine engine = spi.getScriptEngine();
                engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
                return engine;
            } catch (Exception exp) {
                if (DEBUG) exp.printStackTrace();
            }
        }

        for (ScriptEngineFactory spi : engineSpis) {
            List<String> names = null;
            try {
                names = spi.getNames();
            } catch (Exception exp) {
                if (DEBUG) exp.printStackTrace();
            }

            if (names != null) {
                for (String name : names) {
                    if (shortName.equals(name)) {
                        try {
                            ScriptEngine engine = spi.getScriptEngine();
                            engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
                            return engine;
                        } catch (Exception exp) {
                            if (DEBUG) exp.printStackTrace();
                        }
                    }
                }
            }
        }

        return null;
    }
    /**
     * Registers a <code>ScriptEngineFactory</code> to handle a language
     * name.  Overrides any such association found using the Discovery mechanism.
     * @param name The name to be associated with the <code>ScriptEngineFactory</code>.
     * @param factory The class to associate with the given name.
     * @throws NullPointerException if any of the parameters is null.
     */
    public void registerEngineName(String name, ScriptEngineFactory factory) {
        if (name == null || factory == null) throw new NullPointerException();
        nameAssociations.put(name, factory);
    }

所以可以看到有两种方式可以找到ScriptEngine

ScriptEngineFactory是通过ServiceLoader机制来进行加载的,看下Groovy跟Scala各自的实现都是啥,

javax.script.ScriptEngineFactory文件内容分别是,

org.codehaus.groovy.jsr223.GroovyScriptEngineFactory
scala.tools.nsc.interpreter.IMain$Factory

没有找到有调用registerEngineName方法,那就看下各自的getNames方法吧,GroovyScriptEngineFactory的,

    private static final String SHORT_NAME = "groovy";

    private static final String LANGUAGE_NAME = "Groovy";
    static {
        List<String> n = new ArrayList<String>(2);
        n.add(SHORT_NAME);
        n.add(LANGUAGE_NAME);
        NAMES = Collections.unmodifiableList(n);

        n = new ArrayList<String>(1);
        n.add("groovy");
        EXTENSIONS = Collections.unmodifiableList(n);

        n = new ArrayList<String>(1);
        n.add("application/x-groovy");
        MIME_TYPES = Collections.unmodifiableList(n);
    }

所以可以通过"groovy"或者"Groovy"来拿到Groovy的ScriptEngine。看下IMain

    @BeanProperty
    val names: JList[String] = asJavaList("scala")

alright,那就是通过"scala"来拿到了。代码在后面,两种方式一起上。

Shell

通过groovy.lang.GroovyShellIMain都可以直接执行脚本,这两个就是上面我们说的脚本语言提供的API。

我们可以在脚本语言提供的shell环境执行试试,

$ sudo groovy/bin/groovysh
[sudo] password for blues:
Feb 3, 2015 12:36:43 AM org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule newModule
WARNING: Module [groovy-nio] - Unable to load extension class [org.codehaus.groovy.runtime.NioGroovyMethods]
Groovy Shell (2.4.0, JVM: 1.6.0_33)
Type ':help' or ':h' for help.
-----------------------------------------------------------------------------
groovy:000> import groovy.lang.GroovyShell
===> groovy.lang.GroovyShell
groovy:000> groovySh = new GroovyShell()
===> [email protected]
groovy:000> groovySh.evaluate("import java.util.Random; random = new Random(); random.nextInt();")
===> -1378717507
$ scala
Welcome to Scala version 2.11.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.tools.nsc.interpreter._
import scala.tools.nsc.interpreter._

scala> val iMain = new IMain()
iMain: scala.tools.nsc.interpreter.IMain = [email protected]

scala> iMain.eval("import java.util.Random; val random = new Random(); random.nextInt();")
res0: Object = 1320282527

都没有问题。

最后,回到最开始的问题,怎么在Java代码中执行脚本?下面就把两种方式的代码一起贴上,

import groovy.lang.GroovyShell;
import scala.tools.nsc.interpreter.IMain;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Main {

    public static void main(String[] args) throws Exception {
        ScriptEngineManager sem = new ScriptEngineManager();

        String script_groovy =
                "import java.util.Random; random = new Random(); random.nextInt();";

        ScriptEngine se_groovy = sem.getEngineByName("groovy");
        System.out.println(se_groovy.eval(script_groovy));

        GroovyShell groovyShell = new GroovyShell();
        System.out.println(groovyShell.evaluate(script_groovy));

        String script_scala =
                "import java.util.Random; val random = new Random(); random.nextInt();";

        ScriptEngine se_scala = sem.getEngineByName("scala");
        System.out.println(se_scala.eval(script_scala));

        IMain iMain = new IMain();
        System.out.println(iMain.eval(script_scala));

    }

}
1424725324
1691255297
459327395
1109624277

本来想玩下JDK自带的JSR223实现,也就是Nashorn,which is an implementation of the ECMAScript Edition 5.1 Language Specification,但是要到JDK8才有得玩,改天吧^_^
轻拍。

参考资料

时间: 2024-08-03 23:39:18

Scripting Java(一):Java中执行脚本的相关文章

在crontab中执行脚本重要事项

crontab不能成功执行shell脚本的可能原因 crond进程不存在,该进程是crontab的守护进程,它必须存在才能让crontab正常使用: 系统时间不对: 环境变量的问题:crontab执行脚本的时候不会读取用户的环境变量等配置,所以可能很多命令不能使用导致脚本执行失败: 脚本本身的问题. 针对以上几点,在使用crontab之前,我们应该: 检查crond进程是否正在正常运行: 这个很少见,毕竟大多数情况我们的时间都很标准,不过要是用不熟悉的机器,最好还是date一下: 这个应该是最容

TestComplete中执行脚本时控件值未同步刷新问题

今天写了一个程序安装的自动化脚本,调试的时候发现有些控件的值获取后一直未自动刷新,鉴于该问题,仔细分析和请教后,发现TestComplete不会自动刷新控件中变化的值,这需要我们自己去控制刷新. 1.定义一个延迟函数(参数:延迟秒数,执行延迟的条件) Function TimeDelay(DelaySeconds,condition)    Dim interval,startTime    startTime=Time    Do While CBool(condition)        s

Linux中执行脚本参数获取

Linux中变量$[#,@,0,1,2,*,$,?]含义 $# 是传给脚本的参数个数 $0 是脚本本身的名字 $1 是传递给该shell脚本的第一个参数 $2 是传递给该shell脚本的第二个参数 [email protected] 是传给脚本的所有参数的列表 $* 是以一个单字符串显示所有向脚本传递的参数,与位置变量不同,参数可超过9个 $$ 是脚本运行的当前进程ID号 $? 是显示最后命令的退出状态,0表示没有错误,其他表示有错误 区别:[email protected], $* 相同点:都

在Powershell中禁止执行脚本

在Powershell中执行脚本时,有如下报错: 无法加载文件 F:\script\1.ps1,因为在此系统中禁止执行脚本.有关详细信息,请参阅 "get-help about_signing". 所在位置 行:1 字符: 8 + .\1.ps1 <<<< + CategoryInfo          : NotSpecified: (:) [], PSSecurityException + FullyQualifiedErrorId : RuntimeExc

ssh连接远程主机执行脚本的环境变量问题

用ssh命令ssh [email protected] "/web/tomcat-7000/bin/startup.sh" 登陆到远程机器remote上执行脚本时,遇到一个奇怪的问题:tomcat服务不能启动 Neither the JAVA_HOME nor the JRE_HOME environment variable is definedAt least one of these environment variable is needed to run this progr

FileMaker中的脚本学习

FileMaker中的脚本使用 何为脚本: 脚本由一系列的有序步骤组成,为了达到某一确定目标.可使重复的任务简单化或者某些任务自动执行等 在创建一个脚本之前,你需要知道你需要达成的目的. 脚本的创建和管理: 1.通过快捷键CTRL_SHIFT+S来打开管理脚本对话框,有相应的新增,删除,编辑操作可供选择 2.脚本有操作平台的区别,在建立脚本时,请注意兼容平台 3.在编辑或撰写脚本时,或脚本名称后面带有*号,则表示该脚本有进行过操作而没有保存 脚本的触发: 可能通过6种途径来触发脚本 1.File

Java通过SSH2协议执行远程Shell脚本(ganymed-ssh2-build210.jar)

 该工具Jar包可在:http://download.csdn.net/detail/shenjianox/7769783及文档下载地址 ganymed-ssh2简介: Ganymed SSH-2 for Java是用纯Java实现SSH-2协议的一个包.在使用它的过程中非常容易,只需要指定合法的用户名口令, 或者授权认证文件,就可以创建到远程Linux主机的连接,在建立起来的会话中调用该Linux主机上的脚本文件,执行相关操作. 使用方法: 将 ganymed-ssh2-build210.

java中执行js代码

要在java中执行js代码,首先明白,java不支持浏览器本身的方法.支持自定义的js方法,否则会报错 先新建一个js文件:jsss.js 内容如下: function aa(a,b){ return a+b; } 然后在java中写代码: public class ZipTest { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineMa

java中执行系统命令

java程序中执行系统命令猛击下面的链接看看你就知道怎么用了 http://blog.csdn.net/a19881029/article/details/8063758 http://wuhongyu.iteye.com/blog/461477/ http://www.blogjava.net/fastzch/archive/2008/07/08/213477.html