在Java中使用Python脚本



在Java中想使用脚本 需要学习javax.script 包下的内容

在package-summary 中很清楚的介绍了各个类以及接口的作用


接口摘要
Bindings 所有键均为 String 的键/值对映射关系。
Compilable 由 ScriptEngines 实现的可选接口,该 ScriptEngines 的方法将脚本编译成无需重新编译就能反复执行的某种形式。
Invocable 由 ScriptEngines 实现的可选接口,该 ScriptEngines 的方法允许在以前执行过的脚本中调用程序。
ScriptContext 该接口的实现类被用来连接 Script Engines 和宿主应用程序中的对象(如有范围的 Bindings)。
ScriptEngine ScriptEngine 是基础接口,该接口的方法在此规范的每个实现中都必须具有完整的功能。
ScriptEngineFactory ScriptEngineFactory 用来描述和实例化 ScriptEngine

   

类摘要
AbstractScriptEngine 为几个 eval 方法的变体提供标准实现。
CompiledScript 存储编译结果的类扩展自此类。
ScriptEngineManager ScriptEngineManagerScriptEngine 类实现一个发现和实例化机制,还维护一个键/值对集合来存储所有 Manager 创建的引擎所共享的状态。
SimpleBindings 一个受 HashMap 或其他某些指定 Map 支持的 Bindings 的简单实现。
SimpleScriptContext ScriptContext 的简单实现。


脚本 API 由定义 Java TM Scripting Engines 的接口和类组成,并为它们在 Java 应用程序中的使用提供框架。此 API 供那些希望在其 Java 应用程序中执行用脚本语言编写的程序的应用程序编程人员使用。脚本语言程序通常由应用程序的终端用户提供。

javax.script 包的主要功能有:

  1. 脚本执行:脚本是用作脚本引擎所执行程序的源的字符流。脚本执行使用 ScriptEngineeval 方法和Invocable 接口的方法。

  2. 绑定:此功能允许将 Java 对象作为指定变量公开给脚本程序。BindingsScriptContext 类用于此目的。

  3. 编译:此功能允许反复存储和执行脚本引擎前端所生成的中间代码。这有利于多次执行相同脚本的应用程序。引擎的前端只需要对每个脚本执行一次,而不是每次脚本执行都执行一次,因此这些应用程序可以获得高效率。注意,此功能是可选的,脚本引擎可以选择不实现它。调用者需要使用instanceof 来检查Compilable 接口的可用性。

  4. 调用:此功能允许重用脚本引擎前端所生成的中间代码。编译功能允许重执行中间代码所表示的整个脚本,而调用功能允许重执行脚本中的个别程序/方法。因为对于编译而言,并非所有的脚本引擎都需要提供此功能。调用者必须检查Invocable 的可用性。

  5. 脚本引擎发现和元数据:为脚本 API 编写的应用程序可能对脚本引擎有特定的要求。一些可能需要特定的脚本语言和/或版本,而另一些可能需要特定的实现引擎和/或版本。脚本引擎是以指定方式打包的,从而可以在运行时被发现,并可以查询属性。Engine 发现机制基于Jar 文件规范中描述的 Service 发现机制。脚本引擎实现类打包在 jar 文件中,这些文件包含一个名为META-INF/services/javax.script.ScriptEngineFactory 的文本资源。此资源必须为打包在 jar 文件中的每个ScriptEngineFactory 包含一个行。ScriptEngineManager 包括getEngineFactories 方法,该方法用于获取所有使用此机制发现的ScriptEngineFactory 实例。ScriptEngineFactory 拥有用于查询关于脚本引擎的属性的方法。 


    在了解完上面之后,查看下有那些类实现了ScriptEngineFactory , 只有一个NashornScriptEngineFactory。

    看了下源码 默认是不支持python的,找了一下使用Jython还是可以解决这个问题的。

    根据上面 5.Engine 发现机制基于 Jar 文件规范中描述的 Service 发现机制。脚本引擎实现类打包在 jar 文件中,这些文件包含一个名为 META-INF/services/javax.script.ScriptEngineFactory 的文本资源。

    下完包后在Java中使用Python脚本_第1张图片还是发现了这个家伙,这样就确定其他所有的脚本引擎都是使用这种方式找到的。


    先看下ScriptEngineFactory

    在Java中使用Python脚本_第2张图片

    看到有个Jdk的,还有一个pyhton的。 

    下面就开始上代码了

    来到PyScriptEngineFactory  getNames 中 可以支持使用python 和jython 来获取引擎


    public class testPython {
    
    	private Invocable invocableEngine = null; // 执行引擎
    	private Compilable compEngine = null; // 编译引擎
    	private Map<String, CompiledScript> compiledScripts = null; // 编译结果的脚本
    
    	@Test
    	public void testPython() {
    
    		// 1.创建一个脚本引擎管理器
    		ScriptEngineManager scriptManager = new ScriptEngineManager();
    		// 2.根据名称获取对应的脚本引擎
    		ScriptEngine engine = scriptManager.getEngineByName("python");
    		if (engine != null) {
    
    			if (engine instanceof Invocable) {
    				invocableEngine = (Invocable) engine;
    			}
    			if (engine instanceof Compilable) {
    				compEngine = (Compilable) engine;
    			}
    			compiledScripts = new HashMap<String, CompiledScript>();
    
    			String script;
    			try {
    				// 加载文件内容
    				String fileName = "script/a.py";
    				String methodName = "main";
    				script = Loader.load(new File(fileName), "UTF-8");
    				if (script != null && script.length() > 0) {
    					// 注册脚本
    					if (register(fileName, script)) {
    						// 执行脚本
    						execScript(fileName, methodName, this);
    
    					}
    				}
    			} catch (FileNotFoundException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    
    		}
    
    	}
    
    	/**
    	 * 注册一个脚本文件
    	 * 
    	 * @param fileName
    	 *            脚本文件
    	 * @param script
    	 *            脚本文件内容
    	 * @return
    	 */
    	public boolean register(String fileName, String script) {
    		try {
    			// 这里就不判断路径这些了
    			if (fileName != null && script != null) {
    				CompiledScript cs = compEngine.compile(script);
    				compiledScripts.put(fileName, cs);
    			}
    			return true;
    		} catch (ScriptException e) {
    			System.out.println(e);
    		}
    
    		return false;
    	}
    
    	/**
    	 * 执行脚本
    	 * 
    	 * @param filename
    	 *            文件名
    	 * @param methodName
    	 *            方法名
    	 * @param objs
    	 *            参数
    	 * @return
    	 */
    	public Object execScript(String filename, String methodName, Object... objs) {
    		Object retValue = null;
    		try {
    			CompiledScript cs = compiledScripts.get(filename);
    			if (cs != null) {
    
    				cs.eval(); // 执行脚本
    				// 调用Python中的方法
    				retValue = invocableEngine.invokeFunction(methodName, objs);
    			}
    		} catch (ScriptException e) {
    			e.printStackTrace();
    		} catch (NoSuchMethodException e) {
    			e.printStackTrace();
    		}
    		return retValue;
    	}
    
    	public void addPlayer(Player p) {
    		if (p != null) {
    			System.out.println(p.getAge());
    		}
    	}
    
    }



    from script import Player
    def main(testPython):
    	
    	# 创建Java中的对象
    	p = Player()
    	p.setAge(12)
    	print 'hello world'
    	# 调用testPython.java的方法   在Python 中空值是None
    	testPython.addPlayer(p)
    	return








     


你可能感兴趣的:(在Java中使用Python脚本)