您现在的位置是:首页 > 文章详情

《一切皆是映射:代码的本质》Java 动态读取源代码,并编译 & 加载执行

日期:2018-09-13点击:405

动态的执行一段简单代码,采用生成java文件,调用javac编译,反射执行的方式。

使用输入输出流(或者你说的可能是要用反射得到程序结果来解析)解析做出*.Java文件。
然后可以使用runtime调用Dos下的java编译命令编译取得class文件。
然后使用classloader,反射等组合执行生成的class文件。

package loadjarclass; import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import org.junit.Test; public class LoadJarClassTest { @Test public void testLoadClass() throws Exception{ /*动态加载指定类*/ File file=new File("D:/test");//类路径(包文件上一层) URL url=file.toURI().toURL(); ClassLoader loader=new URLClassLoader(new URL[]{url});//创建类加载器 //import com.sun.org.apache.bcel.internal.util.ClassLoader; //ClassLoader classLoader = new ClassLoader(new String[]{""});//类路径 Class<?> cls=loader.loadClass("loadjarclass.TestTest");//加载指定类,注意一定要带上类的包名 Object obj=cls.newInstance();//初始化一个实例 Method method=cls.getMethod("printString",String.class,String.class);//方法名和对应的参数类型 Object o=method.invoke(obj,"chen","leixing");//调用得到的上边的方法method System.out.println(String.valueOf(o));//输出"chenleixing" /*动态加载指定jar包调用其中某个类的方法*/ file=new File("D:/test/commons-lang3.jar");//jar包的路径 url=file.toURI().toURL(); loader=new URLClassLoader(new URL[]{url});//创建类加载器 cls=loader.loadClass("org.apache.commons.lang3.StringUtils");//加载指定类,注意一定要带上类的包名 method=cls.getMethod("center",String.class,int.class,String.class);//方法名和对应的各个参数的类型 o=method.invoke(null,"chen",Integer.valueOf(10),"0");//调用得到的上边的方法method(静态方法,第一个参数可以为null) System.out.println(String.valueOf(o));//输出"000chen000","chen"字符串两边各加3个"0"字符串 } } 

使用com.sun.tools.javac.Main编译Java源代码的,脚本如下。就研究了一番,写了个demo,记录一下,也方便后来人学习。

$ bin/hadoop com.sun.tools.javac.Main WordCount.java $ jar cf wc.jar WordCount*.class 
com.sun.tools.javac.Main 

这个类位于${JAVA_HOME}/lib/tools.jar中,需要添加到classpath中或者直接在IDE中把它引入。这个方式跟直接调用javac命令效果是一样。下面是demo,使用Main类中的compile方法编译一个Person.java源文件后,再加载字节码进行执行。

1、准备待编译的java源代码。

下面代码是一个简单的PersonAction,实现了一个行动接口Action。实现接口不是必须的,只是后面方便实例化一个有具体类型对象才用的。

import inf.Action; public class PersonAction implements Action{ @Override public void say(String msg){ System.out.println("Person say a message: "+msg); } } package inf; public interface Action { public void say(String msg); } 

2、编写执行的代码,该代码用来编译PersonAction.java,编译成功后并加载字节码到JRE中进行执行

 package demo; import inf.Action; import java.io.*; import java.lang.reflect.Method; /** * Created by rns on 17-1-7. */ public class DynamicCompiler { public static void main(String[] args) throws IOException { //待编译的源代码放置的文件夹路径 String basedir = "/home/rns/Desktop/test/"; //待编译的类名称,不包含.java String classname = "PersonAction"; //执行代码的路径,下面的路径是本人的idea编译后输出路径 String executedir = "/home/rns/IdeaProjects_community/" +"DynamicCompileAndRun/out/production/DynamicCompileAndRun/"; //创建编译器 com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main(); //设置编译命令参数,与使用javac命令后面的参数一样 String[] params = new String[] { "-d", basedir,basedir+classname+".java", "-verbose" }; int status = javac.compile(params); //当编译返回值为0时成功 if(status == 0) System.out.println("compiled successfully!"); else System.out.println("errors occurs"); //部署编译好的class到执行目录 copyTo(basedir+classname+".class",executedir+classname+".class"); //加载class字节码并实例化,再调用相应方法 invoke(classname,"say",new Class[]{String.class},new String[]{"Hello"}); } /** * 实例化并调用相应方法 * @param classname 类名 * @param methodname 方法名 * @param paramType 方法参数类型 * @param paramValues 方法参数值 */ public static void invoke(String classname, String methodname, Class[] paramType, Object[] paramValues){ try { Class cls = Class.forName(classname); // 方式一、不转化为具体类型, // 利用反射创建一个Method实例,继而实现方法调用 Method method = cls.getMethod(methodname, paramType); method.invoke(cls.newInstance(),paramValues); // 方式二、转化为具体类型(需要设计相应接口), // 反射实例化后强制转换为接口类型,再进行方法调用 Action person = (Action) cls.newInstance(); person.say(paramValues[0].toString()); } catch (Exception e) { e.printStackTrace(); } } /** * 复制文件到指定目录 * @param from 源文件 * @param to 目的文件 * @throws IOException */ public static void copyTo(String from,String to) throws IOException { FileInputStream fi = new FileInputStream(from); FileOutputStream fo = new FileOutputStream(to); File df = new File(to); if(!df.exists()) df.createNewFile(); for(int read = fi.read(); read !=-1; read=fi.read()){ fo.write(read); } fo.close(); fi.close(); } } 

3、执行结果

/usr/jdk1.8.0_111/bin/java ... compiled successfully! Person say a message: Hello Person say a message: Hello Process finished with exit code 0 
原文链接:https://yq.aliyun.com/articles/662296
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章