java 内嵌Groovy动态脚本操作

网友投稿 302 2022-10-13


java 内嵌Groovy动态脚本操作

固定的策略有时候还是无法满足千变万化的需求变动,一方面需要支持特定的用户需求,另一方面又得尽可能的复用代码,避免重复开发,这就需要将这部分的特殊的需求剥离出来,采用动态配置规则的方式来实现。

java有三种方式调用groovy脚本

但是真正在实际的服务器环境中,嵌入groovy脚本往往需要满足下面的条件:

可以直接调用groovy脚本中的方法

能传递对象到groovy方法中,不仅仅是字符串

提供脚本缓存机制,不用每次调用脚本的时候,都到磁盘读取

修改groovy后能实时生效

第一种:通过GroovyShell来执行groovy脚本

第二种:通过GroovyClassLoader动态加载Groovy Class

第三种:使用GroovyScriptEngine脚本引擎加载Groovy脚本

本实例使用第二种动态加载脚本

Groovy的基本语法

由于Groovy脚本语言能够直接编译成java的class字节码,并且还支持java的类库,运行在java虚拟机上,其能够很好的跟java进行交互,因此利用groovy的动态特性,来实现需求频繁变动的且变态的需求,并且不需要重启服务器。

以下是代码测试control类

package com.webTest.dynamicGroovy.controller;

import groovy.lang.GroovyObject;

import java.io.File;

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

import org.codehaus.groovy.control.CompilationFailedException;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import com.base.common.GroovyUtils;

import com.webTest.dynamicGroovy.bean.GroovyBean;

import com.webTest.dynamicGroovy.groovyInterface.CallBackGroovyInvoke;

import com.webTest.dynamicGroovy.service.CallBackGroovy;

@Controller

@RequestMapping("/groovyTest")

public class GroovyControl {

private Logger logger = Logger.getLogger(GroovyControl.class);

@Autowired

private CallBackGroovy callBackGroovy;

@ResponseBody

@RequestMapping(value="/groovy1.do",method={RequestMethod.GET,RequestMethod.POST})

public Object testGroovy(HttpServletRequest request) throws CompilationFailedException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException{

logger.info("测试动态脚本语言Groovy Begin。。。");

String name="崔春驰";

String realPath = request.getSession().getServletContext().getRealPath("groovyFile");

String groovyNameString = "\\hello.groovy";

String path = realPath+groovyNameString;

File file = new File(path);

//获得class,并存放入堆缓存

Class> groovyClass = GroovyUtils.CLASS_LOADER.parseClass("myFirstGroovy",file,true);

//获取groovyObject的实例

GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();

//反射执行方法,得到返回信息 传多个参数 new Object[]{bean,request,new HashMap<>()}

Object invokeResult = groovyObject.invokeMethod("sayHello", name);

if(invokeResult != null){

System.out.println(invokeResult.toString());

}

//清楚缓存中的map 是为了grrovy脚本变化,清楚堆中缓存,重新类加载

logger.info("测试动态脚本语言Groovy End。。。");

return invokeResult;

}

@ResponseBody

@RequestMapping(value="/groovy2.do",method={RequestMethod.GET,RequestMethod.POST})

public Object testGroovy2(HttpServletRequest request) throws CompilationFailedException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException{

logger.info("测试动态脚本语言Groovy2 Begin。。。");

String realPath = request.getSession().getServletContext().getRealPath("groovyFile");

String groovyNameString = "\\testGroovyBean.groovy";

String path = realPath+groovyNameString;

File file = new File(path);

GroovyBean bean = new GroovyBean();

bean.setNameString("王小二");bean.setAge(12);

Map map = new HashMap<>();

map.put("address", "江苏南京");

//获得class,并存放入堆缓存

Class> groovyClass = GroovyUtils.CLASS_LOADER.parseClass("mySecondGroovy",file,true);

//获取groovyObject的实例

CallBackGroovyInvoke groovyObject = (CallBackGroovyInvoke) groovyClass.newInstance();

//反射执行方法,得到返回信息

Object doCallBackVal = groovyObject.doCallBack(bean, request, map);

if(doCallBackVal instanceof GroovyBean){

GroovyBean bean2 = (GroovyBean) doCallBackVal;

System.out.println("用户信息---》"+bean2.getNameString() + ":"+bean2.getAge()+"岁");

}

System.out.println("统一groovy接口返回数据————————》"+doCallBackVal);

//清楚缓存中的map 是为了grrovy脚本变化,清楚堆中缓存,重新类加载

logger.info("测试动态脚本语言Groovy2 End。。。");

return doCallBackVal;

}

@ResponseBody

@RequestMapping(value="/clearGroovyCache.do",method={RequestMethod.GET,RequestMethod.POST})

public void clearCache(){

//根据指定key来清楚

GroovyUtils.CLASS_LOADER.clearCache("myFirstGroovy");

//清楚所有

GroovyUtils.CLASS_LOADER.clearCache();

}

}

以下为groovyUtils。

public class GroovyUtils {

public static GroovyClassLoaderCommon CLASS_LOADER = null;

static {

CompilerConfiguration configuration = CompilerConfiguration.DEFAULT;

configuration.setSourceEncoding("UTF-8");

CLASS_LOADER = new GroovyClassLoaderCommon(GroovyControl.class.getClassLoader(), configuration);

}

}

以下为GroovyClassLoaderCommon,继承了GroovyClassLoader,主要是重写了,parseClass方法,并且添加了可以清除sourceCache的map缓存,以及可以remove指定的class信息,用于更改groovy文件后,可以及时响应。

package com.webTest.dynamicGroovy;

import groovy.lang.GroovyClassLoader;

import groovy.lang.GroovyCodeSource;

import java.io.File;

import java.io.FileNotFoundException;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import org.codehaus.groovy.control.CompilationFailedException;

import org.codehaus.groovy.control.CompilerConfiguration;

public final class GroovyClassLoaderCommon extends GroovyClassLoader{

//这一步可以放入分布式缓存中,如redis中,统一来管理,防止多次对groovy的变动,可以根据缓存开关来及时的更新到jvm中

private static final Map CACHEMAP_MAP = new ConcurrentHashMap<>();

public GroovyClassLoaderCommon() {

super();

}

public GroovyClassLoaderCommon(ClassLoader loader, CompilerConfiguration config){

super(loader, config);

}

/**

http:// *

* @param file 文件

* @param shouldCacheSource 是否缓存

* @return

* @throws CompilationFailedException

* @throws FileNotFoundException

* Class>

* @author 88397658

* @since

*/

public Class> parseClass(String key,File file,

boolean shouldCacheSource) throws CompilationFailedException, FileNotFoundException {

GroovyCodeSource codeSource = new GroovyCodeSource(file);

codeSource.setCachable(shouldCacheSource);

if(shouldCacheSource) CACHEMAP_MAP.put(key, codeSource.getName());

return super.parseClass(codeSource);

}

/**

* 清楚缓存

*/

public void clearCache(){

synchronized (this) {

sourceCache.clear();

}

}

/**

* 清楚指定缓存

* @param key

* void

* @author 88397658

* @since

*/

public void clearCache(String key){

Object value = CACHEMAP_MAP.get(key);

synchronized (this) {

if(sourceCache.containsKey(value)) sourceCache.remove(value);

if(CACHEMAP_MAP.containsKey(key)) CACHEMAP_MAP.remove(key);

}

}

}

import java.util.Date;

def sayHello(name){

println name+"向你说 “你好!!”";

def date = new Date();

return "success sayHello()+test groovy" +date;

}

sayHello('asda');

import com.webTest.dynamicGroovy.groovyInterface.CallBackGroovyInvoke;

import javax.servlet.http.HttpServletRequest;

import java.util.Map;

import com.webTest.dynamicGroovy.bean.GroovyBean;

import org.slf4j.Logger

import org.slf4j.LoggerFactory

class testGroovyBean implements CallBackGroovyInvoke{

public static final Logger LOGGER = LoggerFactory.getLogger(testGroovyBean.class);

def doCallBack(GroovyBean bean ,HttpServletRequest request, Map map){

LOGGER.info("groovy 中记录日志。。。。");

println "测试接口groovy 获取用户信息:"+bean.getNameString() + " ;年龄:"+bean.getAge();

println "设置用户信息:";

bean.setNameString("蛮王");bean.setAge(200);

def map1 = ['name':'王大锤','sex':'男'];

map = map+map1+['weight':'160'];

def str = otherMethod();

LOGGER.info(str);

// return map

return bean;

}

def otherMethod(){

println "在不重启应用的情况下,调用内部其他方法";

return "我进入了,另一个方法!";

}

}

以上就是测试的这些,至于其框架使用的map容器作为缓存,因jvmGC不会对该容器进行清除,所以为防止内存溢出,可采用自定义的缓存策略,如基于容量、基于时间、基于java对象引用、基于缓存算法(LRU最近最少使用、LFU最不常用、FIFO先进先出),可不用groovy中的容器,及设置缓存设为false,则不放入容器,然后将其生成的实例可放入分布式缓存中redis即可。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:反射内存 RFM5565 分散/集聚的 DMA 操作示例
下一篇:反射内存安装使用方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~