zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    6.8
    6.7
    6.2
    6.1儿童节
    5.24
    5.22
    5.18
    5.17
    Visual Studio开始一个HelloWorld的enclave程序
    以太坊MPT树的HP(Hex-Prefix)编码
  • 原文地址:https://www.cnblogs.com/shirui/p/9402272.html
Copyright © 2011-2022 走看看