Ad-16:易变的业务使用脚本语言编写
1)脚本语言的优势:
a)灵活:脚本语言一般是动态类型,可以不声明变量类型而直接使用, 也可以在运行期间改变类型;
b)便捷:脚本语言是一种解释型语言, 不需要编译成二进制代码,也不需要Java一样生成字节码,它依赖解释器解释的, 运行期间变更代码更容易,而且不用停止业务;
c)简单:部分脚本语言简单易使用。
2)Java 6开始支持脚本语言,JCP(Java Community Process)提出JSR223规范,只要符合该规范的语言都可以在Java上运行;
3)Java默认支持JavaScript语言;
4)由于脚本语言的灵活性和Java对脚本语言的支持,因此在非常易变的业务逻辑中,使用脚本语言来写,然后交给Java来运行;Java处理相对稳定的业务,这样可以带来的好处是不修改重启可以修改业务逻辑;
5)Java 6 不仅提供了代码级的脚本内置,同时还提供了JavaScript命令工具,可以在批处理中发挥更大的作用,而且不需要通过JVM解释脚本语言;
Java执行JavaScript脚本
Java代码:
public class JavaScriptRunner
{
public void running(String jsFile, String funcName, int factor)
{
//获取一个JavaScript执行引擎
ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("javascript");
//建立上下文变量
Bindings bind = engine.createBindings();
bind.put("factor", factor);
//绑定上下文,作用域是当前引擎范围
engine.setBindings(bind, ScriptContext.ENGINE_SCOPE);
Scanner input = new Scanner(System.in);
while (input.hasNext())
{
int first = input.nextInt();
int sec = input.nextInt();
System.out.println("Input is: " + first + ", " + sec);
try
{
//执行js代码
engine.eval(new FileReader(jsFile));
}
catch (FileNotFoundException e1)
{
e1.printStackTrace();
}
catch (ScriptException e1)
{
e1.printStackTrace();
}
//是否有可调用的方法
if (engine instanceof Invocable)
{
Invocable in = (Invocable) engine;
Double result = null;
try
{
//执行JS的函数,注意放回值必须是Double
result = (Double) in.invokeFunction(funcName, first, sec);
}
catch (ScriptException e)
{
e.printStackTrace();
}
catch (NoSuchMethodException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Reuslt = " + result.intValue());
}
}
}
public static void main(String[] argv)
{
String jsFile = "f://formula.js";
String funcName = "formula";
int factor = 3;
JavaScriptRunner runner = new JavaScriptRunner();
runner.running(jsFile, funcName, factor);
}
}
JavaScript代码:
function formula(var1, var2)
{
return var1 + var2 * factor;
}
Ad-17:谨慎使用动态编译
1)Java 6 开始支持动态编译,即在运行期间直接编译.java文件,而不是.class,并且能够获取输入和输出,还能监听相关事件;
2)只要在本地编译能实现的任务,例如:编译参数、输入输出、错误控制等,动态编译也都能实现;
3)Java动态编译可以提供多种渠道,如:字符串,文本文件,字节码文件(.class);
4)不建议使用动态编译,但是对于业务可以变化部分,可以作为采用动态编译执行;
Java动态编译:
public class DynamicCompiler
{
public static class StringJavaObject extends SimpleJavaFileObject
{
private String codeText = null;
public StringJavaObject(String javaFileName, String codeText)
{
super(createStringJavaObjectURI(javaFileName), Kind.SOURCE);
this.codeText = codeText;
}
private static URI createStringJavaObjectURI(String javaFileName)
{
return URI.create("String:///" + javaFileName + Kind.SOURCE.extension);
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException
{
return this.codeText;
}
}
public void compileAndRun(String sourceSrc, String className, String funcName)
{
//当前编译器
JavaCompiler jCmp = ToolProvider.getSystemJavaCompiler();
//Java标准文件管理器
StandardJavaFileManager sJFM = jCmp.getStandardFileManager(null, null, null);
//Java文件对象
JavaFileObject jFO = new StringJavaObject(className, sourceSrc);
//编译参数,类似于javac <options>中的options
List<String> optionsList = new ArrayList<String>();
//编译的class文件存放的位置, 注意:此处为Eclipse工具特设
optionsList.addAll(Arrays.asList("-d", "./bin"));
//编译单元
List<JavaFileObject> jfos = Arrays.asList(jFO);
//设置编译环境
JavaCompiler.CompilationTask task = jCmp.getTask(null, sJFM, null, optionsList, null, jfos);
//编译成功
if (task.call())
{
Object obj = null;
String str = null;
try
{
//生成对象
obj = Class.forName(className).newInstance();
Class<? extends Object> cls = obj.getClass();
//调用方法
Method m = cls.getMethod(funcName, String.class);
str = (String)m.invoke(obj, "Dynamic Compilation");
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (SecurityException e)
{
e.printStackTrace();
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
System.out.println(str);
}
}
public static void main(String[] argv)
{
String codeText = "public class Hello{public String sayHello(String name){ return \"Hello,\" + name + \"!\";}}";
String className = "Hello";
String funcName = "sayHello";
DynamicCompiler compiler = new DynamicCompiler();
compiler.compileAndRun(codeText, className, funcName);
}
}