0

我正在开发一个 java spring 应用程序,我需要提供在不更改标准代码的情况下添加新代码的能力。

我的挑战:

  1. 将“自定义”代码存储在数据库中
  2. 在执行时将代码注入现有的标准代码
  3. 隔离自定义代码,以便两个用户不会执行彼此的代码。

换句话说,我正在寻找的是在方法执行时,如果用户有此方法的自定义代码,请查看数据库,如果没有,则执行标准代码;如果是,则注入代码,执行修改后的方法,然后处理自定义代码。

我看过 AspectJ 和 Javassist。我有一个使用 AspectJ 的过程,但如果自定义代码在它自己的 jar 中并在构建/运行时添加,我只能让它工作。我没有花太多时间在 Javassist 上,但从文档来看,我似乎在同一条船上。

这是我想要做的一个非常简化的例子。

@RestController
@RequestMapping("/test")
public class TestController {
   @RequestMapping(value = "/test", method = RequestMethod.GET)
   public String test() {

      String results = "";

      results = "foo";

      //<-- insert custom code here (if exists) each time method is invoked

      results += "bar";

      return results;
   }
}
4

1 回答 1

2

至于根据 JSR-223 的 Java 脚本支持,这里有一些介绍性文档

默认情况下,Nashorn JavaScript 引擎包含在 JRE 中,但从 Java 11 开始,您会收到一条警告说它已被弃用,并将在未来被删除。这不是一个大问题,因为您仍然可以使用它,而且还有其他与 JSR-223 兼容的脚本语言可用。

这个例子展示了如何使用

  • JavaScript,
  • 时髦的和
  • 卢阿

来自 Java 的脚本。请确保添加相应的

如果您想使用额外的两种语言而不仅仅是内置的 JS 引擎,请将库添加到您的类路径中。

每种语言的脚本都展示了相同的基础知识,即如何

  • File.getCanonicalPath()从脚本调用 Java 对象 ( ) 的方法,
  • 如何将字符串转换为大写,
  • 如何重复一个字符串(在 JS 中我们必须为此定义我们自己的原型方法,因为 Nashorn 本身并没有实现该repeat(n)方法)。
package de.scrum_master.app;

import java.io.File;
import javax.script.*;

public class Application {
  private static final ScriptEngineManager MANAGER = new ScriptEngineManager();

  public static void main(String[] args) throws ScriptException {
    listScriptingEngines();
    System.out.println(runScript("JavaScript", "print(file.getCanonicalPath()); String.prototype.repeat = function(num) { return new Array(num + 1).join(this) }; (text.toUpperCase() + '_').repeat(2)"));
    System.out.println(runScript("Groovy", "println file.canonicalPath; (text.toUpperCase() + '_') * 2"));
    System.out.println(runScript("lua", "print(file:getCanonicalPath()); return string.rep(string.upper(text) .. '_', 2)"));
  }

  public static void listScriptingEngines() {
    for (ScriptEngineFactory factory : MANAGER.getEngineFactories()) {
      System.out.printf("Script Engine: %s (%s)%n", factory.getEngineName(), factory.getEngineVersion());
      System.out.printf("  Language: %s (%s)%n", factory.getLanguageName(), factory.getLanguageVersion());
      factory.getNames().stream().forEach(name -> System.out.printf("    Alias: %s%n", name));
    }
  }

  public static String runScript(String language, String script) throws ScriptException {
    ScriptEngine engine = MANAGER.getEngineByName(language);
    // Expose Java objects as global variables to script engine
    engine.put("file", new File("/my/" + language + "/test.txt"));
    engine.put("text", language);
    // Use script result for generating return value
    return engine.eval(script) + "suffix";
  }
}

如果您在类路径上使用 groovy-all 运行程序,输出应如下所示:

Script Engine: Groovy Scripting Engine (2.0)
  Language: Groovy (2.4.13)
    Alias: groovy
    Alias: Groovy
Script Engine: Luaj (Luaj-jse 3.0.1)
  Language: lua (5.2)
    Alias: lua
    Alias: luaj
Script Engine: Oracle Nashorn (1.8.0_211)
  Language: ECMAScript (ECMA - 262 Edition 5.1)
    Alias: nashorn
    Alias: Nashorn
    Alias: js
    Alias: JS
    Alias: JavaScript
    Alias: javascript
    Alias: ECMAScript
    Alias: ecmascript
C:\my\JavaScript\test.txt
JAVASCRIPT_JAVASCRIPT_suffix
C:\my\Groovy\test.txt
GROOVY_GROOVY_suffix
C:\my\lua\test.txt
LUA_LUA_suffix

当然,在您自己的代码中,您应该将内联 JS、Groovy 或 Lua 代码替换为从您的代码片段数据库中加载的特定于用户的代码。您还应该考虑要向脚本引擎公开哪些变量并为您的用户记录它。

于 2019-08-09T06:37:22.623 回答