JDK6动态编译的方法是什么
JDK6动态编译的方法是什么
这篇文章主要介绍“JDK6动态编译的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JDK6动态编译的方法是什么”文章能帮助大家解决问题。
JDK6开始提供了动态编译的API,在许多应用场景都可以用得着,如动态加载(修改)服务、高性动态业务逻辑实现(用脚本或模板引擎实现效率满足不了需求)等都非常好用。
API对应的接口都在javax.tools包下面,常用编译方式有基于文本文件、内存字符串等,实际上基于URI的字节流都可以,也就是远程Java源代码也可以。对于常用的已有文件形式的动态编译网上的实例已经非常多,我在这里介绍下动态编译内存中以字符串的形式。
简单的代码流程如下:
Java代码
//通过系统工具提供者获得动态编译器JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();//获得一个文件管理器,它的功能主要是提供所有文件操作的规则,//如源代码路径、编译的classpath,class文件目标目录等,其相关属性都提供默认值StandardJavaFileManagerfileManager=compiler.getStandardFileManager(null,null,null);//获得CompilationTask并调用//获得CompilationTask方法原型:getTask(Writerout,JavaFileManagerfileManager,DiagnosticListener<?superJavaFileObject>diagnosticListener,Iterableoptions,Iterableclasses,Iterable<?extendsJavaFileObject>compilationUnits)//简单调用例子booleanb=jc.getTask(null,fileManager,null,null,null,compilationUnits).call();
我这里介绍的字符串形式的编译(其它方式也会有相似的具体实现),还需要提供一个FileObject一个实现类,将相应的对象封装作为getTask()的最后一个参数来构建具体的编译Task.
JavaDoc提供的一个FileObject参考实现:
Class JavaSourceFromString
Java代码
importjava.net.URI;importjavax.tools.SimpleJavaFileObject;publicclassJavaSourceFromStringextendsSimpleJavaFileObject{/***源码*/finalStringcode;/***构造方法:从字符串中构造一个FileObject*@paramnamethenameofthecompilationunitrepresentedbythisfileobject*@paramcodethesourcecodeforthecompilationunitrepresentedbythisfileobject*/JavaSourceFromString(Stringname,Stringcode){super(URI.create("string:///"+name.replace('.','/')+Kind.SOURCE.extension),Kind.SOURCE);this.code=code;}@OverridepublicCharSequencegetCharContent(booleanignoreEncodingErrors){returncode;}}
完整的测试类:
Class TestDyCompile
Java代码
importjava.io.File;importjava.io.IOException;importjava.util.Arrays;importjavax.tools.JavaCompiler;importjavax.tools.JavaFileManager.Location;importjavax.tools.JavaFileObject;importjavax.tools.StandardJavaFileManager;importjavax.tools.StandardLocation;importjavax.tools.ToolProvider;importdyclass.Test;publicclassTestDyCompile{/****@authorZhangXiang*@paramargs*2011-4-7*/publicstaticvoidmain(String[]args){StringBuilderclassStr=newStringBuilder("packagedyclass;publicclassFooimplementsTest{");classStr.append("publicvoidtest(){");classStr.append("System.out.println(\"Foo2\");}}");JavaCompilerjc=ToolProvider.getSystemJavaCompiler();StandardJavaFileManagerfileManager=jc.getStandardFileManager(null,null,null);Locationlocation=StandardLocation.CLASS_OUTPUT;File[]outputs=newFile[]{newFile("bin/")};try{fileManager.setLocation(location,Arrays.asList(outputs));}catch(IOExceptione){e.printStackTrace();}JavaFileObjectjfo=newJavaSourceFromString("dyclass.Foo",classStr.toString());JavaFileObject[]jfos=newJavaFileObject[]{jfo};Iterable<?extendsJavaFileObject>compilationUnits=Arrays.asList(jfos);booleanb=jc.getTask(null,fileManager,null,null,null,compilationUnits).call();if(b){//如果编译成功try{Testt=(Test)Class.forName("dyclass.Foo").newInstance();t.test();}catch(InstantiationExceptione){e.printStackTrace();}catch(IllegalAccessExceptione){e.printStackTrace();}catch(ClassNotFoundExceptione){e.printStackTrace();}}}}
我在这里的具体业务类为dyclass.Foo,也就是我们需要动态编译的类,为了方便写业务的调用代码,也可以让我们的业务类实现一个接口,然后通过反射获得具体子类强制转换来调用。
Test接口:
Java代码
publicinterfaceTest{//业务方法签名voidtest();}
另外,在代码中还有这么一段:
Java代码
Locationlocation=StandardLocation.CLASS_OUTPUT;File[]outputs=newFile[]{newFile("bin/")};try{fileManager.setLocation(location,Arrays.asList(outputs));}catch(IOExceptione){e.printStackTrace();}
这段代码的作用相信大家一看到它就想到它的作用了,前面有说过JavaFileManager 的作用,我在这里设置了CLASS文件的输出目录,意图很简单,我的工程是在Eclipse运行的,项目的目标路径就是项目下的bin目录,如果不设置的话,class文件输出路径即为默认值,也就是直接在项目根路径下,后面直接调用就不能完成了。当然在其它一些应用场景中需要设置为自己需要的目录。
同样的方法可以设置JavaFileManager 其它的我们需要的文件规则属性(可以参照枚举类型StandardLocation),在这里就不一一介绍了。
关于“JDK6动态编译的方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。
推荐阅读
-
jdk8中怎么使用stream实现对象属性的合并
-
JDK里的经典设计模式有哪些
JDK里的经典设计模式有哪些本篇内容介绍了“JDK里的经典设计模式...
-
jdk中try-with-resources怎么用
jdk中try-with-resources怎么用这篇文章主要介绍...
-
java小工具都有哪些
java小工具都有哪些java小工具都有哪些,很多新手对此不是很清...
-
JDK和CGLib动态代理怎么实现
-
关于JDK+Tomcat+eclipse+MyEclipse的配置方法,看这篇够了
关于JDK+Tomcat+eclipse+MyEclipse的配置方法,看这篇够了Eclipse最新版本EclipseNeo...
-
如何正确的使用JDK线程池和Spring线程池
这期内容当中小编将会给大家带来有关如何正确的使用JDK线程池和Spring线程池,文章内容丰富且以专业的角度为大家分析和叙述,阅读...