编写脚本电脑怎么编写界面_在任何无法理解的情况下,请编写脚本

编写脚本电脑怎么编写界面

脚本编写是使您的应用程序在运行时就可根据客户需求进行调整的最流行的方法之一。 与往常一样,此方法不仅带来好处,例如,在灵活性和可管理性之间存在众所周知的折衷方案。 本文不是从理论上讨论优缺点的文章之一,它实际上展示了如何采用脚本的不同方式,并介绍了一个Spring库,该库提供了方便的脚本基础结构和有用的功能。

介绍

脚本(又称插件架构)是使应用程序在运行时可自定义的最直接方法。 通常,脚本不是偶然进入设计的,而是偶然进入应用程序的。 说,您在功能规范中有一个非常不清楚的部分,因此为了避免浪费一天来进行额外的业务分析,我们决定创建一个扩展点并调用一个实现存根的脚本,这将阐明以后的工作方式。

使用这种方法有很多众所周知的利弊:例如,在运行时定义业务逻辑的灵活性非常高,并且可以节省大量的重新部署时间,而无法进行全面的测试,因此,安全性,性能问题是无法预测的问题等等。

对于已经决定在其Java应用程序中坚持使用脚本插件的人,或者只是考虑将其添加到其代码中的人,进一步讨论的脚本编写方法可能会有所帮助。

没什么特别的,只是脚本

使用Java的JSR-233 API,用Java评估脚本是一项简单的任务。 为此API实现了许多生产级评估引擎(Nashorn,JRuby,Jython等),因此向Java代码中添加一些脚本魔术不是问题,如下所示:

Map parameters = createParametersMap();ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine scriptEngine = manager.getEngineByName("groovy");Object result = scriptEngine.eval(script.getScriptAsString("discount.groovy"), new SimpleBindings(parameters));

显然,当代码库中有多个脚本文件和一个调用时,将这样的代码分散在整个应用程序中并不是一个好主意,因此您可以将此代码段提取到放置到实用程序类的单独方法中。 有时,您甚至可以走得更远:您可以创建一个特殊的类(或类集),以基于业务域将脚本化的业务逻辑分组,例如PricingScriptService类。 这将使我们将对validateGroovy ()的调用包装到一个不错的强类型方法中,但是仍然有一些样板代码,所有方法都将包含参数映射,脚本文本加载逻辑和脚本评估引擎调用,类似于以下内容:

public BigDecimal applyCustomerDiscount(Customer customer, BigDecimal orderAmount) {Map params = new HashMap<>();params.put("cust", customer);params.put("amount", orderAmount);return (BigDecimal)scripting.evalGroovy(getScriptSrc("discount.groovy"), params);
}

这种方法在了解参数类型和返回值类型方面带来了更大的透明度。 并且不要忘了在编码标准文档中添加禁止“未包装”脚本引擎调用的规则!

类固醇脚本

尽管使用脚本引擎非常简单,但是如果代码库中有很多脚本,您可能会遇到一些性能问题。 举个例子–您使用Groovy模板进行报告并同时运行许多报告。 迟早您会发现“简单”脚本正在成为性能瓶颈。

这就是为什么某些框架在现有API上构建自己的脚本引擎的原因,并添加了一些不错的功能以实现更好的性能,执行监视,多语言脚本等。

例如,在CUBA框架中,有一个相当复杂的脚本引擎,该引擎实现了一些功能来改善脚本的实现和执行,例如:

  1. 类缓存以避免重复的脚本编译。
  2. 能够使用Groovy和Java语言编写脚本。
  3. 用于脚本引擎管理的JMX bean。

所有这些都提高了性能和可用性,但是它们仍然是用于创建参数映射,获取脚本文本等的低级API,因此,我们仍然需要将它们分组为高阶模块,以在应用程序中有效地使用脚本。

更何况是不提及新的实验性GraalVM引擎及其允许使用其他语言扩展Java应用程序的多语言API。 因此,也许我们会看到Nashorn早晚退休,并且能够在相同的源文件中使用不同的编程语言进行编写,但是将来仍然如此。

Spring框架:很难拒绝的提议?

在Spring Framework中,我们对JDK的API提供了内置的脚本支持,您可以在org.springframework.scripting。*包中找到很多有用的类。 这里有评估人员,工厂等。所有构建您自己的脚本支持所需的工具。

除了底层API之外,Spring Framework的实现还应简化应用程序中脚本的处理-您可以按照文档中的描述定义以动态语言实现的bean。

您需要做的就是使用动态语言(例如Groovy)实现一个类,并在配置XML中描述一个bean,如下所示:

<lang:groovy id="messenger" script-source="classpath:Messenger.groovy"><lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>

之后,您可以使用XML config将Messenger Bean注入到您的应用程序类中。 可以在基础脚本更改的情况下自动“刷新”该bean,并与AOP等一起使用。

这种方法看起来不错,但是作为开发人员,如果您想利用动态语言支持的所有功能,则应该为您的bean实现成熟的类。 在现实生活中,脚本可能只是纯函数,因此您需要向脚本中添加一些额外的代码,以使其与Spring兼容。 如今也有一些开发人员认为XML配置与注释相比是“过时的”,并试图避免使用它,因为Bean定义和注入在Java代码和XML代码之间进行了划分。 尽管它更多是一个品味问题,而不是性能/兼容性/可读性等问题,但我们可以考虑到它。

脚本:挑战和想法

因此,一切都有其代价,当您向应用程序中添加脚本时,您可能会遇到一些挑战:

  1. 可管理性–通常,脚本分散在应用程序中,因此很难管理大量的valuateGroovy (或类似)调用。
  2. 可发现性–如果调用脚本中出现问题,则很难在源代码中找到实际要点。 我们应该能够在IDE中轻松找到所有脚本调用点。
  3. 透明度–编写脚本扩展不是一件容易的事,因为没有有关发送到脚本的变量的信息,也没有有关应返回的结果的信息。 最后,脚本只能由开发人员完成并且只能查看源代码。
  4. 测试和更新–部署(更新)新脚本始终很危险,没有回滚的方法,也没有工具可以在生产前进行测试。

似乎在常规Java方法下隐藏脚本化方法调用可以解决大多数这些挑战。 首选方式–注入“脚本化” bean并使用有意义的名称调用其方法,而不是仅从实用工具类中调用另一个“ eval”方法。 因此,我们的代码正变得自我记录,开发人员无需查看文件“ disc_10_cl.groovy”即可确定参数名称,类型等。

另一个优势–如果所有脚本都有与之关联的唯一Java方法,则可以使用IDE中的“查找用法”功能轻松找到应用程序中的所有扩展点,以及了解该脚本的参数及其含义。返回。

这种执行脚本的方式也使测试变得更加简单–我们不仅能够“照常”测试这些类,而且还可以在需要时使用模拟框架。

所有这些都使我们想起了本文开头提到的方法–脚本方法的“特殊”类。 而且,如果我们更进一步,并隐藏开发人员对脚本引擎,参数创建等的所有调用,该怎么办?

脚本存储库概念

这个想法非常简单,并且所有使用Spring Framework的开发人员都应该熟悉。 我们只是创建一个Java接口并将其方法以某种方式链接到脚本。 例如,Spring Data JPA使用类似的方法,其中接口方法根据方法名称转换为SQL查询,然后由ORM引擎执行。

我们可能需要执行什么概念?

可能是一个类级别的注释,它将帮助我们检测脚本存储库接口并为其构造一个特殊的Spring bean。

方法级别的注释将帮助我们将方法链接到其脚本实现。

最好为该方法提供一个默认实现,它不是简单的存根,而是业务逻辑的有效部分。 在我们实现由业务分析师开发的算法之前,该方法将一直有效。 或者我们可以让他/她编写此脚本:-)

假设您需要创建一个服务来根据用户个人资料计算折扣。 而且业务分析师说,我们可以放心地假设默认情况下可以为所有注册客户提供10%的折扣。 对于这种情况,我们可能会考虑以下代码概念:

@ScriptRepository
public interface PricingRepository {@ScriptMethoddefault BigDecimal applyCustomerDiscount(Customer customer,BigDecimal orderAmount) {return orderAmount.multiply(new BigDecimal("0.9"));}
}

当涉及适当的折扣算法实现时,groovy脚本将如下所示:

-------- file discount.groovy --------
def age = 50
if ((Calendar.YEAR - cust.birthday.year) >= age) {return amount.multiply(0.75)
}
--------

所有这些的最终目标–让开发人员仅实现唯一的接口和折扣算法脚本,并且不要迷失所有这些“ getEngine”和“ eval”调用。 脚本解决方案应该发挥所有魔力:当方法被调用时,拦截调用,查找并加载脚本文本,对其进行评估并返回结果(或者,如果找不到脚本文本,则执行默认方法)。 理想用法应与此类似:

@Service
public class CustomerServiceBean implements CustomerService {@Injectprivate PricingRepository pricingRepository;//Other injected beans here@Overridepublic BigDecimal applyCustomerDiscount(Customer cust, BigDecimal orderAmnt) {if (customer.isRegistered()) {return pricingRepository.applyCustomerDiscount(cust, orderAmnt);} else {return orderAmnt;}//Other service methods here}

脚本调用是可读的,我猜想任何Java开发人员都熟悉脚本的调用方式。

这些就是想法,它们被用来为使用Spring Framework实现脚本存储库创建一个库。 该库具有用于从不同来源加载和评估脚本文本的功能,以及一些API,允许开发人员在需要时实现库的扩展。

这个怎么运作

该库引入了一些注释(以及那些喜欢它的人的XML配置),这些注释在上下文初始化期间为所有标记有@ScriptRepository注释的存储库接口启动动态代理构建。 这些代理以实现存储库接口的单例bean的形式发布,这意味着您可以使用@Autowired@Inject将这些代理完全注入到您的bean中,如上一节中的代码片段所示。

在应用程序配置类之一上使用@EnableSpringRepositories批注可激活脚本存储库。 这种方法类似于其他熟悉的Spring注释,例如@EnableJpaRepositories或@EnableMongoRepositories。 并且对于此批注,您需要指定应类似于JPA存储库进行扫描的软件包名称数组。

@Configuration
@EnableScriptRepositories(basePackages = {"com.example", "com.sample"})
public class CoreConfig {
//More configuration here.
}

如前所示,我们需要使用@ScriptMethod标记脚本存储库中的每个方法(库还提供@GroovyScript@JavaScript ),以将元数据添加到这些调用中并指示这些方法已编写脚本。 当然,还支持脚本方法的默认实现。 解决方案的所有组件都显示在下图中。 蓝色形状与应用程序代码相关,白色形状与库相关。 Spring Bean标记有春天徽标。

脚本编写

调用接口的脚本化方法时,该代理类将拦截该代理类,该代理类将对两个bean执行查找-提供程序以实现脚本文本,以及评估程序以获取结果。 脚本评估后,结果将返回到调用服务。 提供程序和评估程序都可以在@ScriptMethod批注属性以及执行超时中指定(尽管库提供了这些属性的默认值):

@ScriptRepository
public interface PricingRepository {@ScriptMethod (providerBeanName = "resourceProvider",evaluatorBeanName = "groovyEvaluator",timeout = 100)
default BigDecimal applyCustomerDiscount(@ScriptParam("cust") Customer customer,@ScriptParam("amount") BigDecimal orderAmount) {return orderAmount.multiply(new BigDecimal("0.9"));
}
}

您可能会注意到@ScriptParam批注–我们需要它们为方法的参数提供名称。 这些名称应在脚本中使用,因为Java编译器会在编译时删除实际的参数名称。 您可以省略这些注释,在这种情况下,您需要将脚本的参数命名为“ arg0”,“ arg1”等,这会影响代码的可读性。

默认情况下,该库具有可从两种脚本语言的文件系统和基于JSR-233的评估程序读取groovy和javascript文件的提供程序。 但是,您可以为不同的脚本存储和执行引擎创建自定义提供程序和评估程序。 所有这些功能都基于Spring框架接口( org.springframework.scripting.ScriptSourceorg.springframework.scripting.ScriptEvaluator ),因此您可以重用所有基于Spring的类,例如StandardScriptEvaluator而不是默认类。

提供程序(以及评估程序)以Spring Bean的形式发布,因为脚本存储库代理为了灵活性而按名称解析它们-您可以用新的executor代替默认的执行程序,而无需更改应用程序代码,而是在应用程序上下文中替换一个Bean。

测试和版本控制

由于可以轻松更改脚本,因此我们需要确保在更改脚本时不会破坏生产服务器。 该库与JUnit测试框架兼容,没有什么特别的。 由于您在基于Spring的应用程序中使用脚本,因此可以将单元测试和集成测试作为应用程序的一部分来测试脚本,然后再将其上传到生产环境,因此还支持模拟。

另外,您可以创建一个脚本提供程序,以从数据库甚至从Git或其他源代码控制系统读取不同的脚本文本版本。 在这种情况下,如果生产中出现问题,则很容易切换到较新的脚本版本或回滚到以前的脚本版本。

结论

该库将帮助您在代码中安排脚本,提供以下内容:

  1. 通过引入Java接口,开发人员始终可以获得有关脚本参数及其类型的信息。
  2. 提供程序和评估程序可帮助您摆脱分散在应用程序代码中的脚本引擎调用。
  3. 通过使用“查找用法(引用)” IDE命令或仅通过方法名称进行简单的文本搜索,我们可以轻松地在应用程序代码中找到所有脚本用法。

在此Spring Boot的基础上,还支持自动配置,您还可以使用熟悉的单元测试和模拟技术,在将脚本部署到生产之前测试脚本。

该库具有用于在运行时获取脚本元数据(方法名称,参数等)的API,如果您希望避免编写try..catch块来处理脚本抛出的异常,则可以获取包装的执行结果,它还支持XML配置,如果您希望以这种格式存储配置。

另外,可以通过注释中的超时参数来限制脚本执行时间。

可以在https://github.com/cuba-rnd/spring-script-repositories找到库资源。

翻译自: https://www.javacodegeeks.com/2018/11/incomprehensible-situation-scripting.html

编写脚本电脑怎么编写界面

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

stack java实现_Stack (堆栈)使用JAVA实现

代码如下&#xff1a;import java.util.AbstractList;import java.util.Arrays;import java.util.Iterator;import java.util.List;import java.util.RandomAccess;public class Stack extends AbstractListimplements List, RandomAccess, Cloneable, java.io.Serializable{pr…

HTML特殊符号/特殊字符

注&#xff1a;实体名称大小写敏感 点击查看更多特殊字符

访客模式 无痕模式 区别_旧访客设计模式的新生活

访客模式 无痕模式 区别介绍 访客 [1、2]是众所周知的经典设计模式。 有很多资源对其进行了详细说明。 在不深入研究实现的情况下&#xff0c;我将简要提醒一下该模式的概念&#xff0c;解释其优点和缺点&#xff0c;并提出一些可以使用Java编程语言轻松应用于其的改进。 古典…

HTML的图片标签img的图片地址

使用相对路径&#xff0c;例如&#xff0c;当前目录中的子目录 image 中的图片 1.jpg&#xff0c;可以写成 ./image/1.jpg&#xff0c;其中 ./ 表示当前目录&#xff0c;可以省略不写。 <img src"image/1.jpg"/>实际上HTML文档数据写入到 Response 中时&#…

java swing 左上角图标_科学网—Matlab: 学习GUI(修改窗口左上角图标而不warning) - 刘磊的博文...

网上常用的方法&#xff1a;if ~isdeployednewIconjavax.swing.ImageIcon(.piciap.jpg);elsenewIconjavax.swing.ImageIcon(iap.jpg);endjFrame get(hObject,javaframe);jFrame.setFigureIcon(newIcon);运行后warning&#xff1a;Warning: figure JavaFrame property will be …

pbfunc外部扩展函数_从外部CorDapp扩展和覆盖流

pbfunc外部扩展函数Corda 4于上周&#xff08;2月21日&#xff09;发布&#xff0c;带来了大量的新功能&#xff0c;使Corda更加令人愉快。 老实说&#xff0c;我有点假设有很多新功能。 我快速浏览了变更日志&#xff0c;主要是看到我的贡献被引用&#xff0c;但是我记得看到很…

表单项标签的input标签的单选框(radio)

<input type"radio" name"gender" value"male"> 男 <input type"radio" name"gender" value"female"> 女1.单选框需要注意的是&#xff0c;如果是属于一组的选项&#xff0c;那么 name 属性的值必须相…

java 6 update 3_Java(TM) 6 Update(java运行环境) V 6.0.450.6 官方版

Java(TM) 6 Update是个JAVA辅助软件&#xff0c;它具备高度的安全性以及跨平台的特性&#xff0c;能让你的电脑或手机运行java程序&#xff0c;用户可使用Java(TM) 6 Update来搭建甚至运行整个ava程序&#xff0c;注意&#xff1a;卸载后JAVA环境的程序将无法运行。过去很可能会…

jep290涉及jdk版本_JDK 9 / JEP 280:字符串串联永远不会相同

jep290涉及jdk版本JEP 280 &#xff08;“ Indify String Concatenation”&#xff09;是与JDK 9一起实现的&#xff0c;根据其“摘要”部分&#xff0c;“更改了javac生成的静态String concatenation字节码序列&#xff0c;以使用对JDK库函数的invokedynamic调用。 ” 通过查看…

label标签/标记

label 标签用于指定表单项的文字描述信息&#xff0c;如下所示&#xff1a; <label for"username">用户名称&#xff1a;</label> <input id"username" name"username">label 标签 的 for 属性指定的值与 input 标签的 id 属…

矩阵累积相乘 java_累积:轻松自定义Java收集器

矩阵累积相乘 javaAccumulative是针对Collector<T, A, R>的中间累积类型A提出的接口Collector<T, A, R>以使定义自定义Java Collector更加容易。 介绍 如果您曾经使用过Java Stream &#xff0c;那么很可能会使用了一些Collector &#xff0c;例如&#xff1a; C…

java socket 传输压缩文件_java基于socket传输zip文件功能示例

本文实例讲述了java基于socket传输zip文件的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;服务器端程序&#xff1a;import java.io.*;import java.net.*;import java.io.BufferedInputStream;public class SocketServer {ServerSocket ssnull;Socket snull;Dat…

css的学习

文章目录内联样式内部样式外部样式CSS语法格式选择器基本选择器ID 选择器元素选择器类选择器不带标签名带标签名通用选择器并集选择器选择器的优先级扩展选择器组合选择器属性选择器伪类选择器伪元素选择器css 是 Cascading Style Sheets&#xff0c;层叠样式表。 层叠含义是多…

java throws catch_java异常处理throws throw try-catch实例

java异常处理throws throw try-catch实例。throw用于方法中&#xff0c;我们可以预见的错误。比如&#xff1a;if(age<0){Exception e new Exception();//创建异常对象throw e;//抛出异常}在java代码中如果发生异常的话&#xff0c;jvm会抛出异常对象&#xff0c;导致程序代…

java 开发人员工具_每个Java开发人员都应该知道的10个基本工具

java 开发人员工具大家好&#xff0c;我们已经到了2019年的第二个月&#xff0c;我相信你们所有人都已经制定了关于2019年学习以及如何实现这些目标的目标。 我一直在撰写一系列文章&#xff0c;为您提供一些知识&#xff0c;使您可以学习和改进以成为2019年更好的全方位开发人…

SpringBoot2.x+mybatis plus3.x集成Activit7版本

文/朱季谦 在Activiti6版本当中&#xff0c;若要集成到Springboot里&#xff0c;需要写一些额外的配置类&#xff0c;我曾经在Activiti工作流框架学习笔记&#xff08;二&#xff09;之springboot2.0整合工作流Activiti6.0一文当中总结过相关配置过程&#xff0c;感兴趣的同学…

camel apache_Apache Camel 3的工作终于开始了

camel apache我们正在开始Apache Camel 3的工作。 我们正在多方面努力改善骆驼并引入新功能。 Guillaume Nodet实际上是在10月初开始了第一项工作&#xff0c;他通过清理代码库&#xff0c;删除不推荐使用的代码和组件&#xff0c;改进了路由引擎和核心中的其他内部组件开始了…

(前端开发)表格中的行全选、全不选、反选以及数据行背景色变换的示例代码

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>表格数据行全选/全不选/反选的示例</title><style>table {border: 1px solid;width: 500px;margin-left: 30%;}th, td {text-align: cente…

future java 多线程_Java多线程之Future与FutureTask

一&#xff1a;Future在使用实现Callable创建线程时&#xff0c;call()方法是有返回值的。那么&#xff0c;我们在编程时用什么来代表这个 线程执行后才能返回的未来结果 呢&#xff1f;那就是 Future类型。顾名思义&#xff0c;Future——未来值&#xff0c;我们用这个未来值来…

switch字符串jdk_从JDK 12删除原始字符串文字

switch字符串jdk已经提出从JDK 12中删除原始字符串文字&#xff08;预览&#xff09; &#xff08;它将在12月13日进入Rampdown第一阶段 &#xff09;。 Brian Goetz撰写了删除此预览功能的动机的详细说明 &#xff08; JEP 326 &#xff09;。 在Java subreddit上也对此进行了…