• Java_脚本引擎_01_用法入门


    一、前言

    最近有个需求,需要在js中调用java,这样能避免更新java,从而实现代码的热更新。

    于是想到用 Nashorn JavaScript 引擎。

    二、概述

    通过 JDK 8 的 Nashorn JavaScript 引擎 ,可以很方便的实现在java中调用js,以及在js中调用java。

    三、简单示例

    1.java中调用js

        @Test
        public void testDemo1() throws ScriptException {
            //1.创建引擎
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("JavaScript");
    
            //2.要执行的脚本
            String script = "var sum = n1 + n2;print(msg + ' n1= '+ n1 + '; n2 ='+ n2 + '; sum=' + sum);";
            manager.put("n1", 1);
    
            //3.执行脚本
            //3.1 直接传参,并执行脚本
            engine.put("n2", 2);             //使用put(key,value)直接传参到到脚本中,在脚本中通过key来取值
            engine.put("msg", "a string");
            engine.eval(script);
    
            //3.2 通过绑定传参,并执行脚本
            Bindings bindings = engine.createBindings();
            bindings.put("n2", 3);              // AbstractScriptEngine.put(key,value)的内部实现就是使用的Bindings.put(key,value)
            bindings.put("msg", "another string");
            engine.eval(script, bindings);
    
            //3.3 通过上下文来传参,并执行脚本
            ScriptContext ctx = new SimpleScriptContext();
            Bindings ctxGlobalBindings = engine.createBindings();
            ctx.setBindings(ctxGlobalBindings, GLOBAL_SCOPE);
            ctx.setAttribute("n1", 4, GLOBAL_SCOPE);
            ctx.setAttribute("n2", 5, ENGINE_SCOPE);
            ctx.setAttribute("msg", "ScriptContext:", ENGINE_SCOPE);
            engine.eval(script, ctx);  //使用指定上下文来执行脚本
    
            engine.eval(script);   //使用默认上下文执行脚本
        }
    View Code

    2.js中调用java

    HelloWorld.java

    public class HelloWorld {
    
        public void sayHello(){
            System.out.println("hello");
        }
    }
    View Code

    测试用例:

        @Test
        public void test2() throws ScriptException {
            //1.创建引擎
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("JavaScript");
    
            //2.设置要执行的脚本
            String script="$hello.sayHello();";
    
            //3.传参,并执行脚本
            engine.put("$hello", new HelloWorld());
            engine.eval(script);  //使用指定上下文来执行脚本
            
        }
    View Code

    3.通过js实现java接口

    参见:Java脚本教程 - Java脚本实现接口

    四、脚本引擎类结构图

    脚本引擎相关源码的类和接口如下:

    先关注这几个基本实现类

    1. ScriptEngineManager

    源码如下:

    /*
     * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     */
    
    package javax.script;
    import java.util.*;
    import java.security.*;
    import java.util.ServiceLoader;
    import java.util.ServiceConfigurationError;
    
    /**
     * The <code>ScriptEngineManager</code> implements a discovery and instantiation
     * mechanism for <code>ScriptEngine</code> classes and also maintains a
     * collection of key/value pairs storing state shared by all engines created
     * by the Manager. This class uses the <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">service provider</a> mechanism to enumerate all the
     * implementations of <code>ScriptEngineFactory</code>. <br><br>
     * The <code>ScriptEngineManager</code> provides a method to return a list of all these factories
     * as well as utility methods which look up factories on the basis of language name, file extension
     * and mime type.
     * <p>
     * The <code>Bindings</code> of key/value pairs, referred to as the "Global Scope"  maintained
     * by the manager is available to all instances of <code>ScriptEngine</code> created
     * by the <code>ScriptEngineManager</code>.  The values in the <code>Bindings</code> are
     * generally exposed in all scripts.
     *
     * @author Mike Grogan
     * @author A. Sundararajan
     * @since 1.6
     */
    public class ScriptEngineManager  {
        private static final boolean DEBUG = false;
        /**
         * The effect of calling this constructor is the same as calling
         * <code>ScriptEngineManager(Thread.currentThread().getContextClassLoader())</code>.
         *
         * @see java.lang.Thread#getContextClassLoader
         */
        public ScriptEngineManager() {
            ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
            init(ctxtLoader);
        }
    
        /**
         * This constructor loads the implementations of
         * <code>ScriptEngineFactory</code> visible to the given
         * <code>ClassLoader</code> using the <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">service provider</a> mechanism.<br><br>
         * If loader is <code>null</code>, the script engine factories that are
         * bundled with the platform and that are in the usual extension
         * directories (installed extensions) are loaded. <br><br>
         *
         * @param loader ClassLoader used to discover script engine factories.
         */
        public ScriptEngineManager(ClassLoader loader) {
            init(loader);
        }
    
        private void init(final ClassLoader loader) {
            globalScope = new SimpleBindings();
            engineSpis = new HashSet<ScriptEngineFactory>();
            nameAssociations = new HashMap<String, ScriptEngineFactory>();
            extensionAssociations = new HashMap<String, ScriptEngineFactory>();
            mimeTypeAssociations = new HashMap<String, ScriptEngineFactory>();
            initEngines(loader);
        }
    
        private ServiceLoader<ScriptEngineFactory> getServiceLoader(final ClassLoader loader) {
            if (loader != null) {
                return ServiceLoader.load(ScriptEngineFactory.class, loader);
            } else {
                return ServiceLoader.loadInstalled(ScriptEngineFactory.class);
            }
        }
    
        private void initEngines(final ClassLoader loader) {
            Iterator<ScriptEngineFactory> itr = null;
            try {
                ServiceLoader<ScriptEngineFactory> sl = AccessController.doPrivileged(
                    new PrivilegedAction<ServiceLoader<ScriptEngineFactory>>() {
                        @Override
                        public ServiceLoader<ScriptEngineFactory> run() {
                            return getServiceLoader(loader);
                        }
                    });
    
                itr = sl.iterator();
            } catch (ServiceConfigurationError err) {
                System.err.println("Can't find ScriptEngineFactory providers: " +
                              err.getMessage());
                if (DEBUG) {
                    err.printStackTrace();
                }
                // do not throw any exception here. user may want to
                // manage his/her own factories using this manager
                // by explicit registratation (by registerXXX) methods.
                return;
            }
    
            try {
                while (itr.hasNext()) {
                    try {
                        ScriptEngineFactory fact = itr.next();
                        engineSpis.add(fact);
                    } catch (ServiceConfigurationError err) {
                        System.err.println("ScriptEngineManager providers.next(): "
                                     + err.getMessage());
                        if (DEBUG) {
                            err.printStackTrace();
                        }
                        // one factory failed, but check other factories...
                        continue;
                    }
                }
            } catch (ServiceConfigurationError err) {
                System.err.println("ScriptEngineManager providers.hasNext(): "
                                + err.getMessage());
                if (DEBUG) {
                    err.printStackTrace();
                }
                // do not throw any exception here. user may want to
                // manage his/her own factories using this manager
                // by explicit registratation (by registerXXX) methods.
                return;
            }
        }
    
        /**
         * <code>setBindings</code> stores the specified <code>Bindings</code>
         * in the <code>globalScope</code> field. ScriptEngineManager sets this
         * <code>Bindings</code> as global bindings for <code>ScriptEngine</code>
         * objects created by it.
         *
         * @param bindings The specified <code>Bindings</code>
         * @throws IllegalArgumentException if bindings is null.
         */
        public void setBindings(Bindings bindings) {
            if (bindings == null) {
                throw new IllegalArgumentException("Global scope cannot be null.");
            }
    
            globalScope = bindings;
        }
    
        /**
         * <code>getBindings</code> returns the value of the <code>globalScope</code> field.
         * ScriptEngineManager sets this <code>Bindings</code> as global bindings for
         * <code>ScriptEngine</code> objects created by it.
         *
         * @return The globalScope field.
         */
        public Bindings getBindings() {
            return globalScope;
        }
    
        /**
         * Sets the specified key/value pair in the Global Scope.
         * @param key Key to set
         * @param value Value to set.
         * @throws NullPointerException if key is null.
         * @throws IllegalArgumentException if key is empty string.
         */
        public void put(String key, Object value) {
            globalScope.put(key, value);
        }
    
        /**
         * Gets the value for the specified key in the Global Scope
         * @param key The key whose value is to be returned.
         * @return The value for the specified key.
         */
        public Object get(String key) {
            return globalScope.get(key);
        }
    
        /**
         * Looks up and creates a <code>ScriptEngine</code> for a given  name.
         * The algorithm first searches for a <code>ScriptEngineFactory</code> that has been
         * registered as a handler for the specified name using the <code>registerEngineName</code>
         * method.
         * <br><br> If one is not found, it searches the set of <code>ScriptEngineFactory</code> instances
         * stored by the constructor for one with the specified name.  If a <code>ScriptEngineFactory</code>
         * is found by either method, it is used to create instance of <code>ScriptEngine</code>.
         * @param shortName The short name of the <code>ScriptEngine</code> implementation.
         * returned by the <code>getNames</code> method of its <code>ScriptEngineFactory</code>.
         * @return A <code>ScriptEngine</code> created by the factory located in the search.  Returns null
         * if no such factory was found.  The <code>ScriptEngineManager</code> sets its own <code>globalScope</code>
         * <code>Bindings</code> as the <code>GLOBAL_SCOPE</code> <code>Bindings</code> of the newly
         * created <code>ScriptEngine</code>.
         * @throws NullPointerException if shortName is null.
         */
        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;
        }
    
        /**
         * Look up and create a <code>ScriptEngine</code> for a given extension.  The algorithm
         * used by <code>getEngineByName</code> is used except that the search starts
         * by looking for a <code>ScriptEngineFactory</code> registered to handle the
         * given extension using <code>registerEngineExtension</code>.
         * @param extension The given extension
         * @return The engine to handle scripts with this extension.  Returns <code>null</code>
         * if not found.
         * @throws NullPointerException if extension is null.
         */
        public ScriptEngine getEngineByExtension(String extension) {
            if (extension == null) throw new NullPointerException();
            //look for registered extension first
            Object obj;
            if (null != (obj = extensionAssociations.get(extension))) {
                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> exts = null;
                try {
                    exts = spi.getExtensions();
                } catch (Exception exp) {
                    if (DEBUG) exp.printStackTrace();
                }
                if (exts == null) continue;
                for (String ext : exts) {
                    if (extension.equals(ext)) {
                        try {
                            ScriptEngine engine = spi.getScriptEngine();
                            engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
                            return engine;
                        } catch (Exception exp) {
                            if (DEBUG) exp.printStackTrace();
                        }
                    }
                }
            }
            return null;
        }
    
        /**
         * Look up and create a <code>ScriptEngine</code> for a given mime type.  The algorithm
         * used by <code>getEngineByName</code> is used except that the search starts
         * by looking for a <code>ScriptEngineFactory</code> registered to handle the
         * given mime type using <code>registerEngineMimeType</code>.
         * @param mimeType The given mime type
         * @return The engine to handle scripts with this mime type.  Returns <code>null</code>
         * if not found.
         * @throws NullPointerException if mimeType is null.
         */
        public ScriptEngine getEngineByMimeType(String mimeType) {
            if (mimeType == null) throw new NullPointerException();
            //look for registered types first
            Object obj;
            if (null != (obj = mimeTypeAssociations.get(mimeType))) {
                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> types = null;
                try {
                    types = spi.getMimeTypes();
                } catch (Exception exp) {
                    if (DEBUG) exp.printStackTrace();
                }
                if (types == null) continue;
                for (String type : types) {
                    if (mimeType.equals(type)) {
                        try {
                            ScriptEngine engine = spi.getScriptEngine();
                            engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE);
                            return engine;
                        } catch (Exception exp) {
                            if (DEBUG) exp.printStackTrace();
                        }
                    }
                }
            }
            return null;
        }
    
        /**
         * Returns a list whose elements are instances of all the <code>ScriptEngineFactory</code> classes
         * found by the discovery mechanism.
         * @return List of all discovered <code>ScriptEngineFactory</code>s.
         */
        public List<ScriptEngineFactory> getEngineFactories() {
            List<ScriptEngineFactory> res = new ArrayList<ScriptEngineFactory>(engineSpis.size());
            for (ScriptEngineFactory spi : engineSpis) {
                res.add(spi);
            }
            return Collections.unmodifiableList(res);
        }
    
        /**
         * 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);
        }
    
        /**
         * Registers a <code>ScriptEngineFactory</code> to handle a mime type.
         * Overrides any such association found using the Discovery mechanism.
         *
         * @param type The mime type  to be associated with the
         * <code>ScriptEngineFactory</code>.
         *
         * @param factory The class to associate with the given mime type.
         * @throws NullPointerException if any of the parameters is null.
         */
        public void registerEngineMimeType(String type, ScriptEngineFactory factory) {
            if (type == null || factory == null) throw new NullPointerException();
            mimeTypeAssociations.put(type, factory);
        }
    
        /**
         * Registers a <code>ScriptEngineFactory</code> to handle an extension.
         * Overrides any such association found using the Discovery mechanism.
         *
         * @param extension The extension type  to be associated with the
         * <code>ScriptEngineFactory</code>.
         * @param factory The class to associate with the given extension.
         * @throws NullPointerException if any of the parameters is null.
         */
        public void registerEngineExtension(String extension, ScriptEngineFactory factory) {
            if (extension == null || factory == null) throw new NullPointerException();
            extensionAssociations.put(extension, factory);
        }
    
        /** Set of script engine factories discovered. */
        private HashSet<ScriptEngineFactory> engineSpis;
    
        /** Map of engine name to script engine factory. */
        private HashMap<String, ScriptEngineFactory> nameAssociations;
    
        /** Map of script file extension to script engine factory. */
        private HashMap<String, ScriptEngineFactory> extensionAssociations;
    
        /** Map of script script MIME type to script engine factory. */
        private HashMap<String, ScriptEngineFactory> mimeTypeAssociations;
    
        /** Global bindings associated with script engines created by this manager. */
        private Bindings globalScope;
    }
    View Code

    此类主要有三个作用:

    (1)设置全局变量

    (2)获取脚本引擎

    (3)注册脚本引擎工厂

    (1)设置全局变量

        /** Global bindings associated with script engines created by this manager. */
        private Bindings globalScope;
    
        public void put(String key, Object value) {
            globalScope.put(key, value);
        }
    
        public Object get(String key) {
            return globalScope.get(key);
        }

    可以看到,通过 ScriptEngineManager 设置的变量都绑定到了 globalScope 这个绑定中。

    这里并不能说明这个一个全局绑定。

    再往下看:

     此处设置了绑定的作用域为全局。因此 可通过 ScriptEngineManager  设置全局变量

     (2)获取脚本引擎

    可通过以下方法获取脚本引擎

     

     2. SimpleBindings

    绑定是用来存放变量的。

    simpleBingdings是 绑定的基本实现类,源码如下

    /*
     * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     */
    
    package javax.script;
    
    import java.util.Map;
    import java.util.HashMap;
    import java.util.Collection;
    import java.util.Set;
    
    /**
     * A simple implementation of Bindings backed by
     * a <code>HashMap</code> or some other specified <code>Map</code>.
     *
     * @author Mike Grogan
     * @since 1.6
     */
    public class SimpleBindings implements Bindings {
    
        /**
         * The <code>Map</code> field stores the attributes.
         */
        private Map<String,Object> map;
    
        /**
         * Constructor uses an existing <code>Map</code> to store the values.
         * @param m The <code>Map</code> backing this <code>SimpleBindings</code>.
         * @throws NullPointerException if m is null
         */
        public SimpleBindings(Map<String,Object> m) {
            if (m == null) {
                throw new NullPointerException();
            }
            this.map = m;
        }
    
        /**
         * Default constructor uses a <code>HashMap</code>.
         */
        public SimpleBindings() {
            this(new HashMap<String,Object>());
        }
    
        /**
         * Sets the specified key/value in the underlying <code>map</code> field.
         *
         * @param name Name of value
         * @param value Value to set.
         *
         * @return Previous value for the specified key.  Returns null if key was previously
         * unset.
         *
         * @throws NullPointerException if the name is null.
         * @throws IllegalArgumentException if the name is empty.
         */
        public Object put(String name, Object value) {
            checkKey(name);
            return map.put(name,value);
        }
    
        /**
         * <code>putAll</code> is implemented using <code>Map.putAll</code>.
         *
         * @param toMerge The <code>Map</code> of values to add.
         *
         * @throws NullPointerException
         *         if toMerge map is null or if some key in the map is null.
         * @throws IllegalArgumentException
         *         if some key in the map is an empty String.
         */
        public void putAll(Map<? extends String, ? extends Object> toMerge) {
            if (toMerge == null) {
                throw new NullPointerException("toMerge map is null");
            }
            for (Map.Entry<? extends String, ? extends Object> entry : toMerge.entrySet()) {
                String key = entry.getKey();
                checkKey(key);
                put(key, entry.getValue());
            }
        }
    
        /** {@inheritDoc} */
        public void clear() {
            map.clear();
        }
    
        /**
         * Returns <tt>true</tt> if this map contains a mapping for the specified
         * key.  More formally, returns <tt>true</tt> if and only if
         * this map contains a mapping for a key <tt>k</tt> such that
         * <tt>(key==null ? k==null : key.equals(k))</tt>.  (There can be
         * at most one such mapping.)
         *
         * @param key key whose presence in this map is to be tested.
         * @return <tt>true</tt> if this map contains a mapping for the specified
         *         key.
         *
         * @throws NullPointerException if key is null
         * @throws ClassCastException if key is not String
         * @throws IllegalArgumentException if key is empty String
         */
        public boolean containsKey(Object key) {
            checkKey(key);
            return map.containsKey(key);
        }
    
        /** {@inheritDoc} */
        public boolean containsValue(Object value) {
            return map.containsValue(value);
        }
    
        /** {@inheritDoc} */
        public Set<Map.Entry<String, Object>> entrySet() {
            return map.entrySet();
        }
    
        /**
         * Returns the value to which this map maps the specified key.  Returns
         * <tt>null</tt> if the map contains no mapping for this key.  A return
         * value of <tt>null</tt> does not <i>necessarily</i> indicate that the
         * map contains no mapping for the key; it's also possible that the map
         * explicitly maps the key to <tt>null</tt>.  The <tt>containsKey</tt>
         * operation may be used to distinguish these two cases.
         *
         * <p>More formally, if this map contains a mapping from a key
         * <tt>k</tt> to a value <tt>v</tt> such that <tt>(key==null ? k==null :
         * key.equals(k))</tt>, then this method returns <tt>v</tt>; otherwise
         * it returns <tt>null</tt>.  (There can be at most one such mapping.)
         *
         * @param key key whose associated value is to be returned.
         * @return the value to which this map maps the specified key, or
         *         <tt>null</tt> if the map contains no mapping for this key.
         *
         * @throws NullPointerException if key is null
         * @throws ClassCastException if key is not String
         * @throws IllegalArgumentException if key is empty String
         */
        public Object get(Object key) {
            checkKey(key);
            return map.get(key);
        }
    
        /** {@inheritDoc} */
        public boolean isEmpty() {
            return map.isEmpty();
        }
    
        /** {@inheritDoc} */
        public Set<String> keySet() {
            return map.keySet();
        }
    
        /**
         * Removes the mapping for this key from this map if it is present
         * (optional operation).   More formally, if this map contains a mapping
         * from key <tt>k</tt> to value <tt>v</tt> such that
         * <code>(key==null ?  k==null : key.equals(k))</code>, that mapping
         * is removed.  (The map can contain at most one such mapping.)
         *
         * <p>Returns the value to which the map previously associated the key, or
         * <tt>null</tt> if the map contained no mapping for this key.  (A
         * <tt>null</tt> return can also indicate that the map previously
         * associated <tt>null</tt> with the specified key if the implementation
         * supports <tt>null</tt> values.)  The map will not contain a mapping for
         * the specified  key once the call returns.
         *
         * @param key key whose mapping is to be removed from the map.
         * @return previous value associated with specified key, or <tt>null</tt>
         *         if there was no mapping for key.
         *
         * @throws NullPointerException if key is null
         * @throws ClassCastException if key is not String
         * @throws IllegalArgumentException if key is empty String
         */
        public Object remove(Object key) {
            checkKey(key);
            return map.remove(key);
        }
    
        /** {@inheritDoc} */
        public int size() {
            return map.size();
        }
    
        /** {@inheritDoc} */
        public Collection<Object> values() {
            return map.values();
        }
    
        private void checkKey(Object key) {
            if (key == null) {
                throw new NullPointerException("key can not be null");
            }
            if (!(key instanceof String)) {
                throw new ClassCastException("key should be a String");
            }
            if (key.equals("")) {
                throw new IllegalArgumentException("key can not be empty");
            }
        }
    }
    View Code

    可以发现绑定的内部实现时通过HashMap来实现的。

    Bingding通过HashMap来存放变量。

    3.SimpleScriptContext

    脚本引擎是在脚本上下文中执行的。

    脚本上下文由四个组件组成:

    • 与不同范围相关联的绑定。上下文中的绑定将参数传递给脚本。
    • 读取器读取输入
    • 写入输出
    • 写入错误输出的错误写入器

    绑定是是有作用域的,有两个作用域:

    • ScriptContext.ENGINE_SCOPE       (引擎范围,值为100)
    • ScriptContext.GLOBAL_SCOPE      (全局范围,值为200)

    (1) 设置变量:

        public void setAttribute(String var1, Object var2, int var3) {
            this.checkName(var1);
            switch(var3) {
            case 100:
                this.engineScope.put(var1, var2);
                return;
            case 200:
                if (this.globalScope != null) {
                    this.globalScope.put(var1, var2);
                }
    
                return;
            default:
                throw new IllegalArgumentException("Illegal scope value.");
            }
        }
    
        protected Bindings engineScope = new SimpleBindings();
        protected Bindings globalScope = null;
    View Code

    可以看到全局绑定默认为空。回到 三、简单示例 中,如下:

            //3.3 通过上下文来传参,并执行脚本
            ScriptContext ctx = new SimpleScriptContext();
            Bindings ctxGlobalBindings = engine.createBindings();
            ctx.setBindings(ctxGlobalBindings, GLOBAL_SCOPE);
            ctx.setAttribute("n1", 4, GLOBAL_SCOPE);
            ctx.setAttribute("n2", 5, ENGINE_SCOPE);
            ctx.setAttribute("msg", "ScriptContext:", ENGINE_SCOPE);
            engine.eval(script, ctx);  //使用指定上下文来执行脚本

    设置全局变量的步骤:我们先设置了一个全局绑定,这样全局绑定就不为空,然后再设置全局变量。

     4.ScriptEngine

     ScriptEngine提供了如下接口,

    抽象类AbstractScriptEngine实现了ScriptEngine的部分基本方法。

    脚本引擎实际的执行者 NashornScriptEngine 继承自 AbstractScriptEngine 实现了 ScriptEngine的全部方法,功能强大。

    五、参考资料

    1.Java 脚本引擎—w3cschool

    我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=8rf7kovqfyoo

  • 相关阅读:
    Unity The Method Signature Matching Rule
    Unity The Property Matching Rule
    Unity The Type Matching Rule
    Unity The Custom Attribute Matching Rule
    Unity The Member Name Matching Rule
    Unity No Policies
    Unity The Return Type Matching Rule
    Unity The Parameter Type Matching Rule
    Unity The Namespace Matching Rule
    关于TSQL递归查询的(转)
  • 原文地址:https://www.cnblogs.com/shirui/p/9402272.html
Copyright © 2020-2023  润新知