Scripting Java (2): Use the Spring container, scriptingspring
We already know how to execute the script language in Java. Today, we use Groovy as the chestnut to see how to use Spring containers in the script.
Bindings
The simplest way is to directly drop ApplicationContext to the context of ScriptEngine, that is, Bindings, so that the script can be directly used.ApplicationContext.getBean
To get the bean in the container.
import java.util.Random;public class Foo { private int i; public int getI() { return i; } public Foo bar() { System.out.println("hello Foo."); this.i = new Random().nextInt(); return this; }}
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import javax.script.Bindings;import javax.script.ScriptContext;import javax.script.ScriptEngine;import javax.script.ScriptEngineManager;import java.util.HashMap;import java.util.Map;public class Main { public static void main(String[] args) throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml"); Map<String, Object> params = new HashMap<String, Object>(); params.put("sc", context); ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine se = sem.getEngineByName("groovy"); Bindings bindings = se.createBindings(); bindings.putAll(params); se.setBindings(bindings, ScriptContext.ENGINE_SCOPE); String text = "foo = sc.getBean(\"foo\"); foo.bar();"; System.out.println(((Foo)se.eval(text)).getI()); bindings.clear(); }}
Output,
hello Foo.54704882
Another note is that the return value of the last statement in the script will beScriptEngine#eval
.
DRY
If the above method is used more spring beans, there will be a lotsc.getBean
Such repeated code. Laziness is the virtue of programmers. In order to liberate productivity, we can optimize it.
In the agreed way (COC), when the variable name is__
That is, the variable starting with two underscores indicates that it is a spring bean, and the character after the underscore is the bean name. Then, before the script engine is executed, we only need to replace the regular expression.
public class Main { public static void main(String[] args) throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml"); Map<String, Object> params = new HashMap<String, Object>(); String bindingName_ac = "_springContext"; params.put(bindingName_ac, context); ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine se = sem.getEngineByName("groovy"); Bindings bindings = se.createBindings(); bindings.putAll(params); se.setBindings(bindings, ScriptContext.ENGINE_SCOPE); String text = "__foo.bar(); foo = __foo; foo.getI();"; String replacedText = text.replaceAll("__(\\w*)", bindingName_ac+".getBean(\"$1\")"); System.out.println(replacedText); System.out.println(se.eval(replacedText)); bindings.clear(); }}
The output is as follows,
_springContext.getBean("foo").bar(); foo = _springContext.getBean("foo"); foo.getI();hello Foo.-885362561
Binding has only two scopes: ScriptContext # ENGINE_SCOPE and ScriptContext # GLOBAL_SCOPE. To prevent Binding mutual contamination, after the script is executedbindings.clear()
Be safe.
References
- Http://docs.oracle.com/javase/tutorial/essential/regex/