SoFunction
Updated on 2025-03-08

Java embedded Groovy dynamic script operation

Fixed strategies sometimes cannot meet the ever-changing changes in demand. On the one hand, they need to support specific user needs, and on the other hand, they need to reuse code as much as possible to avoid repeated development. This requires the special needs of this part and the implementation of dynamic configuration rules.

There are three ways to call groovy scripts in Java

However, in a real server environment, embedding groovy scripts often requires the following conditions:

  1. You can directly call methods in groovy scripts
  2. Can pass objects into groovy methods, not just strings
  3. Provides script caching mechanism, which does not require reading to disk every time the script is called.
  4. After modifying groovy, it can take effect in real time

The first type: Execute groovy scripts through GroovyShell

The second type: dynamically load Groovy Class through GroovyClassLoader

The third type: Loading Groovy scripts using GroovyScriptEngine script engine

This example uses the second dynamic loading script

Basic syntax of Groovy

Since the Groovy scripting language can directly compile into Java class bytecode, and also supports Java class libraries. It runs on a Java virtual machine and can interact well with Java. Therefore, the dynamic features of groovy are used to achieve frequent changes in requirements and abnormal requirements, and there is no need to restart the server.

The following is the code to test the control class

package ; 
import ; 
import ;
import ;
import ;
import ;
 
import ; 
import .;
import ;
import ;
import ;
import ;
import ;
import ;
 
import ;
import ;
import ;
import ;
 
@Controller
@RequestMapping("/groovyTest")
public class GroovyControl {	
	private Logger logger = ();		
	@Autowired
	private CallBackGroovy callBackGroovy;		
	@ResponseBody
	@RequestMapping(value="/",method={,})
	public  Object testGroovy(HttpServletRequest request) throws CompilationFailedException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException{
		("Test the dynamic scripting language Groovy Begin....");
		String name="Cui Chunchi";
		String realPath = ().getServletContext().getRealPath("groovyFile");
		String groovyNameString = "\\";
		String path = realPath+groovyNameString;
		File file = new File(path);
		
		//Get the class and store it in the heap cache		Class<?> groovyClass = GroovyUtils.CLASS_LOADER.parseClass("myFirstGroovy",file,true);
		//Get the instance of groovyObject		GroovyObject  groovyObject = (GroovyObject) ();
		//Reflection execution method, get the return information Pass multiple parameters new Object[]{bean,request,new HashMap<>()}		Object invokeResult = ("sayHello", name);
		if(invokeResult != null){
			(());
		}
		//Clear maps in the cache for groovy script changes, clear cache in the heap, and re-class loading.		("Test the dynamic scripting language Groovy End....");
		return invokeResult;
	}
	
	@ResponseBody
	@RequestMapping(value="/",method={,})
	public  Object testGroovy2(HttpServletRequest request) throws CompilationFailedException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException{
		("Test the dynamic scripting language Groovy2 Begin....");
		String realPath = ().getServletContext().getRealPath("groovyFile");
		String groovyNameString = "\\";
		String path = realPath+groovyNameString;
		File file = new File(path);
		
		GroovyBean bean = new GroovyBean();
		("Wang Xiaoer");(12);
		Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();
		("address", "Nanjing, Jiangsu");
		
		//Get the class and store it in the heap cache		Class&lt;?&gt; groovyClass = GroovyUtils.CLASS_LOADER.parseClass("mySecondGroovy",file,true);
		//Get the instance of groovyObject		CallBackGroovyInvoke  groovyObject = (CallBackGroovyInvoke) ();
		//Reflection execution method, get the return information		Object doCallBackVal = (bean, request, map);
		
		if(doCallBackVal instanceof GroovyBean){
			GroovyBean bean2  = (GroovyBean) doCallBackVal;
			("User Information---"+() + ":"+()+"age");
		}
		("Unified groovy interface returns data—————————”+doCallBackVal);
		//Clear maps in the cache for groovy script changes, clear cache in the heap, and re-class loading.		("Test the dynamic scripting language Groovy2 End....");
		return doCallBackVal;
	}
	
	@ResponseBody
	@RequestMapping(value="/",method={,})
	public void clearCache(){
		//Clarify according to the specified key		GroovyUtils.CLASS_LOADER.clearCache("myFirstGroovy");
		//Clear all		GroovyUtils.CLASS_LOADER.clearCache();
	}
}

The following are groovyUtils.

public class GroovyUtils { 
 public static GroovyClassLoaderCommon CLASS_LOADER = null; 
 static {
  CompilerConfiguration configuration = ;
  ("UTF-8");
  CLASS_LOADER = new GroovyClassLoaderCommon((), configuration);
 } 
}

The following is GroovyClassLoaderCommon, which inherits the GroovyClassLoader, mainly rewrites the parseClass method, and adds the map cache that can clear the sourceCache, as well as the class information that can be specified. It can respond in a timely manner after changing the groovy file.

package ; 
import ;
import ; 
import ;
import ;
import ;
import ; 
import ;
import ; 
public final class GroovyClassLoaderCommon extends GroovyClassLoader{
	
	//This step can be put into distributed cache, such as Redis, managed in a unified manner to prevent multiple changes to groovy. You can update it to jvm in time according to the cache switch.	private static final Map&lt;String, Object&gt; CACHEMAP_MAP = new ConcurrentHashMap&lt;&gt;();
	
	public GroovyClassLoaderCommon() {
		super();
	}
	
	public GroovyClassLoaderCommon(ClassLoader loader, CompilerConfiguration config){
		super(loader, config);
	}
	
	/**
	  *
	  * @param file
	  * @param shouldCacheSource Whether to cache
	  * @return
	  * @throws CompilationFailedException
	  * @throws FileNotFoundException
	  * Class<?>
	  * @author 88397658
	  * @since
	  */
	public Class&lt;?&gt; parseClass(String key,File file,
			boolean shouldCacheSource) throws CompilationFailedException, FileNotFoundException {
		GroovyCodeSource codeSource = new GroovyCodeSource(file);
		(shouldCacheSource);
		if(shouldCacheSource) CACHEMAP_MAP.put(key, ());
		return (codeSource);
	}
	
	/**
	  * Clear cache
	  */
	public void clearCache(){
		synchronized (this) {
			();
		}
	}
	/**
	  * Clearly specify the cache
	  * @param key
	  * void
	  * @author 88397658
	  * @since
	  */
	public void clearCache(String key){
		Object value = CACHEMAP_MAP.get(key);
		synchronized (this) {
			if((value)) (value);
			if(CACHEMAP_MAP.containsKey(key)) CACHEMAP_MAP.remove(key);
		}
	} 
}
 
import ; 
def sayHello(name){
	println name+"Say to you "Hello!  !  "";
	def date = new Date();
	return "success sayHello()+test  groovy" +date;
} 
&lt;!--Can be called directly --&gt;
sayHello('asda');
import ;
import ;
import ;
import ;
import org.
import org.
 
class testGroovyBean implements CallBackGroovyInvoke{
	public static final Logger LOGGER = ();	
	def doCallBack(GroovyBean bean ,HttpServletRequest request, Map&lt;String, Object&gt; map){
		("Log logs in groovy....");
		println "Test interface groovy to obtain user information:"+() + " ;age:"+();
		println "Set user information:";
		("Barbha King");(200);
		def map1 = ['name':'Wang Daehn','sex':'male'];
		map = map+map1+['weight':'160'];
		def str =  otherMethod();
		(str);
//		return map
		return bean;
	}
	
	def otherMethod(){
		println "Call other internal methods without restarting the application";
		return "I'm in, another way!";
	}
}

The above are all tested. As for the map container used by its framework as cache, since jvmGC will not clear the container, to prevent memory overflow, custom cache policies can be adopted, such as capacity-based, time-based, java object reference, cache algorithm (LRU is least recently used, LFU is least commonly used, FIFO first-in-first out), you can not use the container in groovy, and set the cache to false, then do not put it in the container, and then the generated instance can be put into the distributed cache redis.

For personal experience only, I hope you can give you a reference and I hope you can support me more.