Java - JSR223规范解读_在JVM上实现多语言支持

文章目录

  • 1. 概述
  • 2. 核心目标
  • 3. 支持的脚本语言
  • 4. 主要接口
  • 5. 脚本引擎的使用
    • 执行JavaScript脚本
    • 执行groovy脚本
      • 1. Groovy简介
      • 2. Groovy脚本示例
      • 3. 如何在Java中集成 Groovy
      • 4. 集成注意事项
  • 6. 与Java集成
  • 7. 常见应用场景
  • 8. 优缺点
  • 9. 总结

在这里插入图片描述

1. 概述

JSR223(Java Specification Request 223),也称为 Scripting for the Java Platform,是一个Java平台的标准接口,旨在让Java应用程序能够灵活地集成和执行脚本语言。它定义了一种可以在Java应用中嵌入不同脚本语言的统一接口,允许Java程序调用、执行脚本,并且支持将Java对象传递到脚本语言中。


2. 核心目标

JSR223的目标是提供一种标准的API,以便Java应用能够:

  • 动态地执行脚本代码
  • 支持多个脚本语言
  • 将Java应用中的对象传递到脚本环境中

3. 支持的脚本语言

JSR223并没有指定哪些脚本语言必须支持,但它的设计理念是能够支持多种脚本语言。常见的支持脚本语言包括:

  • JavaScript (Nashorn / GraalVM)
  • Groovy
  • JRuby
  • Jython (Python)
  • Lua
  • BeanShell

不同的脚本语言通过JSR223接口进行集成,这些脚本引擎作为JSR223的实现进行交互。


4. 主要接口

JSR223定义了几个关键接口来实现Java与脚本语言的交互:

  • ScriptEngine: 这个接口代表了一个脚本引擎,允许Java代码与具体的脚本语言引擎进行交互。每个脚本引擎都实现了这个接口。
  • ScriptEngineFactory: 用于创建脚本引擎的工厂类。通过这个工厂类,Java程序可以获得可用的脚本引擎实例。
  • Bindings: 用于在Java和脚本之间传递变量和对象。Bindings允许在脚本执行期间使用Java对象。

常见的实现类:

  • Nashorn(从Java 8开始包含,用于执行JavaScript)
  • GraalVM(一个多语言执行环境,支持更多语言的集成)

5. 脚本引擎的使用

脚本引擎是JSR223的核心部分,接下来看几个例子

执行JavaScript脚本

样例一: 使用Nashorn引擎执行JavaScript代码的示例。

package com.artisan.jsr223;
import javax.script.*;

public class JSR223Example {
    public static void main(String[] args) throws ScriptException {
        // 创建一个脚本引擎管理器
        ScriptEngineManager manager = new ScriptEngineManager();

        // 获取JavaScript引擎
        ScriptEngine engine = manager.getEngineByName("nashorn");

        // 执行JavaScript代码
        engine.eval("print('Hello, JSR223')");

        // 使用绑定传递变量
        Bindings bindings = engine.createBindings();
        bindings.put("name", "Artisan");
        engine.eval("print('Hello, ' + name);", bindings);
    }
}

在这个例子中,我们通过 ScriptEngineManager 获取Nashorn引擎,执行简单的JavaScript代码,使用 Bindings 传递变量。

在这里插入图片描述


样例二:

package com.artisan.jsr223;

import javax.script.*;

public class JSR223Example {
    public static void main(String[] args) throws Exception {
        // 获得JavaScript的脚本引擎
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
        ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("javascript");

       // 进行脚本编译
        String script = "function process(){\n" +
                "var a=10;\n" +
                "var b=3;\n" +
                "return a*b-c;\n" +
                "}\n" +
                "process()";

       // 检查脚本引擎是否支持编译
        if (scriptEngine instanceof Compilable) {
            Compilable compilable = (Compilable) scriptEngine;
            CompiledScript compiledScript = compilable.compile(script);

            // 绑定Java的参数
            Bindings bindings = new SimpleBindings();
            bindings.put("c", 5);

            // 执行并打印结果
            Object result = compiledScript.eval(bindings);
            System.out.println(result);
        } else {
            System.out.println("当前脚本引擎不支持编译功能");
        }

    }
}

在这里插入图片描述


执行groovy脚本

1. Groovy简介

Groovy是一个基于Java平台的动态语言,它简洁、表达力强,并且与Java兼容性极高。Groovy可以作为Java的脚本引擎,直接在Java应用中使用。Groovy的语法简洁,支持面向对象、闭包、动态类型等特性,通常用于快速开发和扩展功能。

2. Groovy脚本示例

假设我们要编写一个简单的Groovy脚本,来计算一个人的年龄,并根据年龄判断是否符合某个年龄段(如成年)。

// 定义一个函数来计算年龄
def calculateAge(birthYear) {
    def currentYear = 2024
    return currentYear - birthYear
}

// 定义一个函数来判断是否成年
def isAdult(age) {
    return age >= 18
}

// 调用计算年龄和判断是否成年
def birthYear = 1990
def age = calculateAge(birthYear)

println("Age: ${age}")
if (isAdult(age)) {
    println("You are an adult.")
} else {
    println("You are not an adult.")
}

解释:

  • def:用于定义变量或函数,Groovy是一种动态语言,变量和函数不需要显式声明类型。
  • calculateAge:该函数接受一个出生年份,返回计算后的年龄(2024年减去出生年份)。
  • isAdult:根据传入的年龄判断是否成年,成年为18岁及以上。
  • println:Groovy的内建方法,输出结果。

运行结果:

Age: 34
You are an adult.

3. 如何在Java中集成 Groovy

假设我们希望在Java代码中动态执行这个Groovy脚本,可以通过JSR223来实现。以下是如何在Java中嵌入并执行Groovy脚本的示例:


import javax.script.*;

public class GroovyTest {

    public static void main(String[] args) throws ScriptException {
        // 创建一个脚本引擎管理器
        ScriptEngineManager manager = new ScriptEngineManager();

        // 获取Groovy引擎
        ScriptEngine engine = manager.getEngineByName("groovy");

        // 定义Groovy脚本
        String script =
                "def calculateAge(birthYear) { " +
                        "    def currentYear = 2024; " +
                        "    return currentYear - birthYear; " +
                        "}\n" +  // 添加换行符
                        "def isAdult(age) { " +
                        "    return age >= 18; " +
                        "}\n" +  // 添加换行符
                        "def birthYear = 1990; " +
                        "def age = calculateAge(birthYear); " +
                        "println('Age: ' + age); " +
                        "if (isAdult(age)) { " +
                        "    println('You are an adult.'); " +
                        "} else { " +
                        "    println('You are not an adult.'); " +
                        "} ";

        // 执行Groovy脚本
        engine.eval(script);
    }
}

步骤:

  1. 使用 ScriptEngineManager 获取Groovy引擎。
  2. 编写Groovy脚本并将其传递给引擎。
  3. 使用 eval() 方法执行脚本,并输出结果。

运行结果:

Age: 34
You are an adult.

4. 集成注意事项

  • Groovy的依赖:如果在Java项目中使用Groovy脚本,需要将Groovy的JAR包(例如 groovy-jsr223-x.y.z.jar)添加到项目的依赖中。

Maven依赖示例:

   <dependency>
            <groupId>org.apache.groovy</groupId>
            <artifactId>groovy-jsr223</artifactId>
            <version>4.0.24</version>
    </dependency>
  • 性能考虑:Groovy作为动态语言,性能可能不如纯Java代码,特别是在大规模或频繁执行的场景中,可能会引入一定的开销。

6. 与Java集成

  • 变量传递:JSR223允许将Java对象传递给脚本语言。通过 Bindings 接口,可以将Java对象存储在脚本的上下文中,脚本语言也能访问这些对象。

  • 动态执行:使用脚本语言可以动态地执行Java代码段,这对于快速开发和修改业务逻辑非常有效。例如,可以通过Java调用Groovy脚本来快速增加一些动态功能而无需重新编译整个应用。


7. 常见应用场景

JSR223可以广泛应用于多个领域:

  • 动态配置和脚本扩展:在Java应用中使用脚本来动态修改行为。例如,可以用Groovy编写自定义的配置文件解析器。
  • 自动化测试:集成脚本语言用于编写自动化测试脚本。
  • Web应用:在Web应用中,使用JSR223集成脚本语言来编写自定义插件或扩展功能。例如,支持JavaScript来扩展服务器端的业务逻辑。
  • 数据处理:在Java应用中使用脚本来处理数据或执行算法。

8. 优缺点

优点:

  • 灵活性:脚本语言的引入使得Java应用能够动态修改行为,增加了灵活性。
  • 简化开发:无需重新编译整个Java应用,可以动态执行脚本。
  • 多语言支持:能够使用多种脚本语言,适应不同开发者的需求。

缺点:

  • 性能问题:执行脚本语言可能比直接执行Java代码慢,尤其是当脚本频繁执行时。
  • 维护性问题:使用脚本时,可能会增加代码的复杂性,特别是当脚本代码没有很好地组织和文档化时。
  • 调试困难:脚本代码的调试相对困难,尤其是当脚本与Java代码紧密集成时。

9. 总结

JSR223提供了一个标准的接口来将脚本语言集成到Java应用中,支持多个脚本引擎和多种脚本语言的调用。它可以极大地提升Java应用的灵活性和扩展性,尤其适用于动态修改应用行为的场景。然而,使用JSR223时也要注意性能和维护性问题。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/927723.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

oracle数据库的启动与关闭

一.oracle数据库的启动过程 启动实例&#xff08;Start the Instance&#xff09; 启动实例&#xff1a;一个Oracle数据库实例由内存结构和后台进程组成&#xff0c;启动实例时会加载这些内存结构和启动进程。实例是数据库的一个运行时环境&#xff0c;它包含了数据库的控制文…

【C++】自主实现stack/queue

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解C的自主实现stack/queue&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 1. stack2. queue 栈&#xff1a;后进先出 队列&#xff1a;先进先出 栈和队列…

Hive学习基本概念

基本概念 hive是什么&#xff1f; Facebook 开源&#xff0c;用于解决海量结构化日志的数据统计。 基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能 本质是将HQL转化为MapReduce程序。 Hive处理的数据存储在H…

Android studio 签名加固后的apk文件

Android studio打包时&#xff0c;可以选择签名类型v1和v2&#xff0c;但是在经过加固后&#xff0c;签名就不在了&#xff0c;或者只有v1签名&#xff0c;这样是不安全的。 操作流程&#xff1a; 1、Android studio 对项目进行打包&#xff0c;生成有签名的apk文件&#xff…

CSS学习记录03

CSS背景 CSS 背景属性用于定义元素的背景效果。 CSS background-color background-color属性指定元素的背景色。 页面的背景色设置如下&#xff1a; body {background-color: lightblue; } 通过CSS&#xff0c;颜色通常由以下方式指定&#xff1a; 有效的颜色名称-比如“…

Unity类银河战士恶魔城学习总结(P155 More example on audio effects更多的音效细节)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节添加了更多的音效细节 音频管理器 AudioManager.cs 使得多个音效可以同时播放&#xff0c;注释掉以下代码 public void PlaySFX(in…

【分组去重】.NET开源 ORM 框架 SqlSugar 系列

&#x1f4a5; .NET开源 ORM 框架 SqlSugar 系列 &#x1f389;&#x1f389;&#x1f389; 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列…

openwrt利用nftables在校园网环境下开启nat6 (ipv6 nat)

年初写过一篇openwrt在校园网环境下开启ipv6 nat的文章&#xff0c;利用ip6tables控制ipv6的流量。然而从OpenWrt22版本开始&#xff0c;系统内置的防火墙变为nftables&#xff0c;因此配置方法有所改变。本文主要参考了OpenWRT使用nftables实现IPv6 NAT 这篇文章。 友情提示 …

IS-IS的原理

IS-IS的基本概念&#xff1a; 概述&#xff1a; IS-IS&#xff0c;中间系统到中间系统&#xff0c;是ISO国际标准化组织为它的无连接网络协议设计的一种动态路由协议 IS-IS支持CLNP网络和IP网络&#xff0c;采用数据链路层封装&#xff0c;区别于ospf只支持IP网络&#xff0…

006 MATLAB编程基础

01 M文件 MATLAB输入命令有两种方法&#xff1a; 一是在MATLAB主窗口逐行输入命令&#xff0c;每个命令之间用分号或逗号分隔&#xff0c;每行可包含多个命令。 二是将命令组织成一个命令语句文集&#xff0c;使用扩展名“.m”&#xff0c;称为M文件。它由一系列的命令和语句…

hhdb数据库介绍(10-31)

管理 数据恢复 执行数据恢复说明 恢复页面输入正确的恢复信息&#xff0c;提交恢复任务后跳转到恢复页面&#xff0c;任务状态显示“恢复中且有进度更新显示”&#xff0c;此时若触发删除操作&#xff0c;则提示“恢复执行中不能删除” 恢复期间计算节点会暂停服务&#xff…

IntelliJ IDEA配置(mac版本)

用惯了eclipse开发java的小伙伴们&#xff0c;初次接触IntelliJ IDEA可能会和我一样&#xff0c;多少有些不适感&#xff0c;在使用过程中总想着eclipse得对应功能。 接下来&#xff0c;我就总结下我日常开发中遇到的常用配置&#xff08;不包括快捷键&#xff0c;我认为每个人…

基于大数据python 豆果美食推荐数据可视化系统(源码+LW+部署讲解+数据库+ppt)

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 很对人不知道选题怎么选 不清楚自己适合做哪块内容 都可以免费来问我 避免后期給自己答辩找麻烦 增加难度&#xff08;部分学校只有一次答辩机会 没弄好就延迟…

.NET8/.NETCore 依赖注入:自动注入项目中所有接口和自定义类

.NET8/.NETCore 依赖接口注入&#xff1a;自动注入项目中所有接口和自定义类 目录 自定义依赖接口扩展类&#xff1a;HostExtensions AddInjectionServices方法GlobalAssemblies 全局静态类测试 自定义依赖接口 需要依赖注入的类必须实现以下接口。 C# /// <summary>…

视频流媒体服务解决方案之Liveweb视频汇聚平台

一&#xff0c;Liveweb视频汇聚平台简介: LiveWeb是深圳市好游科技有限公司开发的一套综合视频汇聚管理平台&#xff0c;可提供多协议&#xff08;RTSP/RTMP/GB28181/海康Ehome/大华&#xff0c;海康SDK等&#xff09;的视频设备接入&#xff0c;支持GB/T28181上下级联&#xf…

数据结构基础之《(9)—归并排序》

一、什么是归并排序 1、整体是递归&#xff0c;左边排好序右边排好序merge让整体有序 2、让其整体有序的过程里用了排外序方法 3、利用master公式来求解时间复杂度 4、当然可以用非递归实现 二、归并排序说明 1、首先有一个f函数 void f(arr, L, R) 说明&#xff1a;在arr上…

AWS账号提额

Lightsail提额 控制台右上角&#xff0c;用户名点开&#xff0c;选择Service Quotas 在导航栏中AWS服务中找到lightsail点进去 在搜索框搜索instance找到相应的实例类型申请配额 4.根据自己的需求选择要提额的地区 5.根据需求来提升配额数量,提升小额配额等大约1小时生效 Ligh…

[代码随想录06]哈希表的使用,有效字母异位词,两数组交集,快乐数,两数之和

前言 哈希表是什么&#xff1f;一句话带你理解&#xff0c;简单来说我们对于杂乱的数据&#xff0c;怎么快速找到数据&#xff0c;如何做呢&#xff1f;一般的做法就是遍历复杂度为o(N)去找寻一个数据&#xff0c;但是吧&#xff0c;我们这样思考的话&#xff0c;还是花了大量时…

Python 时间和日期

Python 日期和时间 概述时间元组struct_time获取当前时间获取格式化的时间格式化日期日期格式化符号获取某月日历Time 模块日历&#xff08;Calendar&#xff09;模块 概述 Python 提供一个 time 和 calendar 模块可以用于格式化日期和时间。 时间间隔是以秒为单位的浮点小数。…

今天我们来聊聊Maven中两个高级的概念—— 插件和目标

插件&#xff08;plugin&#xff09; Maven的核心是一个插件执行框架;所有的工作都是由插件完成的。 Maven中Plugin分为两种类型&#xff1a; build类型Plugin只能在build阶段执行&#xff0c;在POM中需要在 <build/> 标签下进行配置。 reporting类型&#xff1a;在si…