Java动态 调用Groovy的方法

1、静态编译,在java工程中直接写groovy的文件,然后可以在Groovy的文件中引用Java工程的类,这种方式能够有效的利用groovy自身的语言特性,例如闭包; (这种方式上面已经提及,不适合我们目前需求)
2、通过groovyShell类直接执行脚本,例如:

  1. Binding bind =newBinding();
  2. bind.setVariable("str","test");
  3. GroovyShell shell =newGroovyShell(bind);
  4. Object obj = shell.evaluate("return str");
  5. System.out.println(obj);

3、通过groovyScriptEngine执行文件或者脚本,例如:

  1. GroovyScriptEngine engine =newGroovyScriptEngine("groovy");
  2. Object obj = engine.run("test.groovy","test");
  3. System.out.println(obj);

​4、通过GroovyClassLoader来执行,例如:

  1. String script="";//groovy script
  2. ClassLoader parent =ClassLoader.getSystemClassLoader();
  3. GroovyClassLoader loader =newGroovyClassLoader(parent);
  4. Class<?> clazz = loader.parseClass(script);
  5. GroovyObject clazzObj =(GroovyObject)clazz.newInstance();
  6. System.out.println(clazzObj.invokeMethod("test","str"));

需要注意的是,通过看groovy的创建类的地方,就能发现,每次执行的时候,都会新生成一个class文件,这样就会导致JVM的perm区持续增长,进而导致FullGCc问题,解决办法很简单,就是脚本文件变化了之后才去创建文件,之前从缓存中获取即可,缓存的实现可以采用简单的Map或者使用之前文章提到的EhCache(同时可以设置缓存有效期,降低服务器压力)。

在使用时,最好每次重新new classloader,因为如果脚本重新加载了,这时候就会有新老两个class文件,如果通过一个classloader持有的话,这样在GC扫描的时候,会认为老的类还在存活,导致回收不掉,所以每次new一个就能解决这个问题了。

注意CodeCache的设置大小(来自:http://hellojava.info/)
对于大量使用Groovy的应用,尤其是Groovy脚本还会经常更新的应用,由于这些Groovy脚本在执行了很多次后都会被JVM编译为native进行优化,会占据一些CodeCache空间,而如果这样的脚本很多的话,可能会导致CodeCache被用满,而CodeCache一旦被用满,JVM的Compiler就会被禁用,那性能下降的就不是一点点了。
Code Cache用满一方面是因为空间可能不够用,另一方面是Code Cache是不会回收的,所以会累积的越来越多(其实在不采用groovy这种动态更新/装载class的情况下的话,是不会太多的),所以解法一可以是增大code cache的size,可通过在启动参数上增加-XX:ReservedCodeCacheSize=256m(Oracle JVM Team那边也是推荐把code cache调大的),二是启用code cache的回收机制(关于Code Cache flushing的具体策略请参见此文),可通过在启动参数上增加:-XX:+UseCodeCacheFlushing来启用。

展开阅读全文

没有更多推荐了,返回首页