Java动态从外部加载groovy脚本并执行。因为java可以直接把对象绑定到groovy脚本中执行,所以完全可以把一些系统中不确定的处理留下钩子,用groovy脚本处理,逻辑变了就直接改脚本,不用走发布流程。

核心代码

  1. CompilerConfiguration conf = new CompilerConfiguration();
  2. conf.setDebug(false);
  3. shell = new GroovyShell(conf);
  4. String extCP = "/extlib/xxx.jar";
  5. shell.getClassLoader().addClasspath(extCP);
  6. String scriptName = "Script.groovy";
  7. String scriptText = "String hello(){ return args[0] }";
  8. Script script = (Class<Script>) shell.parse(scriptText, scriptName).getClass();
  9. Thread.currentThread().setContextClassLoader(shell.getClassLoader());
  10. //获取groovy代码中的hello方法
  11. Method method = script.getDeclaredMethod("hello");
  12. Script instance = script.newInstance();
  13. Map bindings = instance.getBinding().getVariables();
  14. bindings.clear();
  15. //绑定args全局变量
  16. bindings.put("args", args);
  17. String ret = method.invoke(instance);
  18. bindings.clear();

依赖

  1. <dependency>
  2. <groupId>org.codehaus.groovy</groupId>
  3. <artifactId>groovy-json</artifactId>
  4. <version>2.5.4</version>
  5. <scope>provided</scope>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.codehaus.groovy</groupId>
  9. <artifactId>groovy-sql</artifactId>
  10. <version>2.5.4</version>
  11. <scope>provided</scope>
  12. </dependency>
  13. <!-- groovy-all does not include groovy-dateutil by default, so must explicitly
  14. include it here -->
  15. <dependency>
  16. <groupId>org.codehaus.groovy</groupId>
  17. <artifactId>groovy-dateutil</artifactId>
  18. <version>2.5.4</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.codehaus.groovy</groupId>
  22. <artifactId>groovy-jsr223</artifactId>
  23. <version>2.5.4</version>
  24. </dependency>

优化

可以根据脚本内容/脚本id等对script / method 来进行缓存,避免每次执行都要编译。编译会有大量的时间消耗,并造成metaspace增长。