昨天線上的代碼調用一個遠端的服務無緣無故不成功,又沒加那麼多日志,不好定位問題,好想線上上執行一下代碼,列印點log看看
于是想着怎麼動态執行點java代碼,忽然想起以前玩過的groovy,于是搞起來
大概思路是這樣,寫一個控制器,接收一段代碼,動态執行,然後傳回執行結果,切記,做好權限控制,免得杯具
沒想到實作起來異常簡單
1、gradle.build加入groovy依賴
compile "org.codehaus.groovy:groovy:2.5.3"
2、寫個工具類,友善拿到spring上下文對象,這個很常見
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContextUtils implements ApplicationContextAware {
static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
SpringContextUtils.context = context;
}
public static ApplicationContext getContext() {
return context;
}
public static void autowireBean(Object bean) {
context.getAutowireCapableBeanFactory().autowireBean(bean);
}
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
}
3、寫個控制器
import com.ruizton.util.SpringContextUtils;
import groovy.lang.GroovyClassLoader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Method;
@RestController
public class GroovyController {
@RequestMapping("/runScript")
public Object runScript(String script) throws Exception {
if (script != null) {
// 這裡其實就是groovy的api動态的加載生成一個Class,然後反射生成對象,然後執行run方法,最後傳回結果
// 最精華的地方就是SpringContextUtils.autowireBean,可以實作自動注入bean,
Class clazz = new GroovyClassLoader().parseClass(script);
Method run = clazz.getMethod("run");
Object o = clazz.newInstance();
SpringContextUtils.autowireBean(o);
Object ret = run.invoke(o);
return ret;
} else {
return "no script";
}
}
}
上面是java的全部内容了,接下來就是調用了
首先準備寫個test.groovy代碼
import org.springframework.beans.factory.annotation.Autowired
class Foo {
@Autowired
FooService fooService;
Object run() {
// do something
def f = fooService.findById(38);
if (f != null) {
return f.name
}
return null
}
}
不寫類直接寫代碼塊也是可以的
test.groovy
def sum = 1 + 2
return "sum = " + sum
上面代碼也會生成一個Class對象,裡面的代碼預設在run方法下面,是以控制器哪裡都是調用的run方法
再寫個python調用一個接口,其實就是讀檔案然後調用一下java的接口,要是不怕死,也可以在背景做一個可視化界面,加個執行按鈕直接調用
test.py
#!/usr/bin/python
import requests
def read(filename):
f = open(filename,'r')
file = f.read()
f.close()
return file
res = requests.post('http://127.0.0.1/runScript.html', data = {
'script': read('test.groovy')
})
print res.text
$ chmod +x test.py
$ ./test.py
大功告成。盡情玩耍吧