java动态编译笔记
1 前言
Java的动态编译知识,真真在实际开发中并不是经常遇到。但是学习java动态编译有助于我们从更深一层次去了解java。对掌握jdk的动态代理模式,这样我们在学习其他一些开源框架的时候就能够知其然也知其所以然。下面我们来使用java的动态编译。有关java动态编译的API都在javax.tools包中
2 使用JavaCompiler接口来编译java源程序
使用 Java API来编译 Java源程序有非常多方法,目前让我们来看一种最简单的方法,通过JavaCompiler进行编译。我们能通过ToolProvider类的静态方法getSystemJavaCompiler来得到一个JavaCompiler接口的实例。
如果前3个参数传入的是null,那么run方法将以标准的输入、输出代替,即System.in、System.out和 System.err。如果我们要编译一个 hello.java文件,并将使用标准输入输出,run的使用方法如下:
完整的代码如下(用的是Eclipse工具)
2.1 Eclipse工程截图
2.2 Hello.java
package my.xyz.hello;
public class Hello {
public static void main(String[] args) {
System.out.println("helloworld!");
}
}
2.3 DynamicCompileTest.java
package my.xyz.test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
public class DynamicCompileTest {
public static void main(String[] args) throws Exception {
// 任务:编译temp目录下的Hello.java文件
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();// 取得当前系统编译器
int result = javaCompiler.run(null, null, null, "-d", "./temp", "./temp/Hello.java");
// int result=javaCompiler.run(null, null, null, "Hello.java");
System.out.println(result == 0 ? "恭喜编译成功!" : "对不起编译失败");
// 在程序中来运行Hello.classs
Runtime run = Runtime.getRuntime();
Process process = run.exec("java -cp ./temp my.xyz.hello.Hello");
InputStream in = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String info = "";
while ((info = reader.readLine()) != null) {
System.out.println(info);
}
}
}
3 使用StandardJavaFileManager编译Java源程序
3.1 Eclipse工程截图
3.2 DynamicCompileTest.java
package my.xyz.test;
import java.io.File;
import java.io.FileWriter;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class DynamicCompileTest {
public static void main(String[] args) throws Exception {
//1.创建需要动态编译的代码字符串
String nr="\r\n";//回车换行
String source="package my.xyz.hello;"+nr+
" public class Hello{"+nr+
" public static void main(String[] args){"+nr+
" System.out.println(\"helloworld!\");"+nr+
"}"+nr+
"}" ;
//2.将预动态编译的代码写入文件中1:创建临时目录 2:写入临时文件
File dir=new File(System.getProperty("user.dir")+"/temp");//临时目录
//如果/temp目录不存在创建temp目录
if(!dir.exists()){
dir.mkdir();
}
FileWriter writer=new FileWriter(new File(dir,"Hello.java"));
writer.write(source);//将字符串写入文件中
writer.flush();
writer.close();
//3:取得当前系统java编译器
JavaCompiler javaCompiler=ToolProvider.getSystemJavaCompiler();
//4:获取一个文件管理器StandardJavaFileManage
StandardJavaFileManager javaFileManager=javaCompiler.getStandardFileManager(null, null, null);
//5.文件管理器根与文件连接起来
Iterable it=javaFileManager.getJavaFileObjects(new File(dir,"Hello.java"));
//6.创建编译的任务
//CompilationTask task=javaCompiler.getTask(null, javaFileManager, null,null, null, it);
CompilationTask task=javaCompiler.getTask(null, javaFileManager, null,Arrays.asList("-d","./temp"), null, it);
//执行编译
task.call();
javaFileManager.close();
}
}
4 从内存中动态编译java程序并动态加载执行
4.1 Eclipse工程截图
4.2 JavaStringObject.java
package my.xyz;
import java.io.IOException;
import java.net.URI;
import javax.tools.SimpleJavaFileObject;
public class JavaStringObject extends SimpleJavaFileObject {
private String code;
public JavaStringObject(String name, String code) {
//super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
super(URI.create(name+".java"), Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return code;
}
}
4.3 DynamicCompileTest.java
package my.xyz.test;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
import my.xyz.JavaStringObject;
public class DynamicCompileTest {
public static void main(String[] args) throws Exception {
/*
* 编译内存中的java代码
*/
// 将代码写入内存中
StringWriter writer = new StringWriter();// 内存字符串输出流
PrintWriter out = new PrintWriter(writer);
out.println("package my.xyz.hello;");
out.println("public class Hello{");
out.println("public static void main(String[] args){");
out.println("System.out.println(\"helloworld!\");");
out.println("}");
out.println("}");
out.flush();
out.close();
// 开始编译
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
JavaFileObject fileObject = new JavaStringObject("Hello", writer.toString());
CompilationTask task=javaCompiler.getTask(null, null, null, Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject));
boolean success=task.call();
if(!success){
System.out.println("编译失败!");
}
else{
System.out.println("编译成功!");
//利用反射调用其中的main()方法
// Class class1=Class.forName("com.ynxinhua.hello.Hello");
//ClassLoader是自动去从当前工作目录下的classpath路径下去找 也就是bin目录下
//Class class1=ClassLoader.getSystemClassLoader().loadClass("my.xyz.hello.Hello");
//利用URLClassLoader去实例化一个Class类 类文件可以放在任意位置,这样就很方便了
URL[] urls=new URL[]{new URL("file:/"+"./bin/")};
URLClassLoader classLoader=new URLClassLoader(urls);
Class class1=classLoader.loadClass("my.xyz.hello.Hello");
Method method=class1.getDeclaredMethod("main",String[].class);
String[] args1={null};
method.invoke(class1.newInstance(),args1);
}
}
}
java动态编译笔记的更多相关文章
- java动态编译 (java在线执行代码后端实现原理)(二)
在上一篇java动态编译 (java在线执行代码后端实现原理(一))文章中实现了 字符串编译成字节码,然后通过反射来运行代码的demo.这一篇文章提供一个如何防止死循环的代码占用cpu的问题. 思路: ...
- java动态编译 (java在线执行代码后端实现原理)
需求:要实现一个web网页中输入java代码,然后能知道编译结果以及执行结果 类似于菜鸟java在线工具的效果:https://c.runoob.com/compile/10 刚开始从什么概念都没有到 ...
- Java动态编译技术原理
这里介绍Java动态编译技术原理! 编译,一般来说就是将源代码转换成机器码的过程,比如在C语言中中,将C语言源代码编译成a.out,,但是在Java中的理解可能有点不同,编译指的是将java 源代码转 ...
- Java 动态编译--DynamicCompiler
java 动态编译自己写过程的机会比较少,记录一下: package com.xzlf.dynamicCompile; import java.io.IOException; import java. ...
- (转载)JAVA动态编译--字节代码的操纵
在一般的Java应用开发过程中,开发人员使用Java的方式比较简单.打开惯用的IDE,编写Java源代码,再利用IDE提供的功能直接运行Java 程序就可以了.这种开发模式背后的过程是:开发人员编写的 ...
- Java动态编译
程序产生过程 下图展示了从源代码到可运行程序的过程,正常情况下先编译(明文源码到字节码),后执行(JVM加载字节码,获得类模板,实例化,方法使用).本文来探索下当程序已经开始执行,但在.class甚至 ...
- java动态编译类文件并加载到内存中
如果你想在动态编译并加载了class后,能够用hibernate的数据访问接口以面向对象的方式来操作该class类,请参考这篇博文-http://www.cnblogs.com/anai/p/4270 ...
- Java 动态编译组件 & 类动态加载
1.JDK6 动态编译组件 Java SE 6 之后自身集成了运行时编译的组件:javax.tools,存放在 tools.jar 包里,可以实现 Java 源代码编译,帮助扩展静态应用程序.该包中提 ...
- 动态代理 原理简析(java. 动态编译,动态代理)
动态代理: 1.动态编译 JavaCompiler.CompilationTask 动态编译想理解自己查API文档 2.反射被代理类 主要使用Method.invoke(Object o,Object ...
随机推荐
- jQuery的几个应例题、JSON基础
1.下拉列表取值.赋值 (1)写个下拉列表,如下: <select id="sel"> <option value="山东">山东< ...
- java调用CXF WebService接口的两种方式
通过http://localhost:7002/card/services/HelloWorld?wsdl访问到xml如下,说明接口写对了. 2.静态调用 // 创建WebService客户端代理工厂 ...
- WCF学习之旅—WCF服务部署到应用程序(十)
上接 WCF学习之旅—WCF寄宿前的准备(八) WCF学习之旅—WCF服务部署到IIS7.5(九) 五.控制台应用程序宿主 (1) 在解决方案下新建控制台输出项目 ConsoleHosting.如下 ...
- 2016-Beijing-GDG-DevFest大会参后感
前话 15年初的时候参加过一次GDG线下举办的一次分享会,因为当时是实习的公司提供的活动场地.有了那次机会后,就一直关注了GDG的活动. 参加的目的最重要的是本次大会是比较盛大的一场技术大会,在经过一 ...
- 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。
最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...
- ASP.NET Core 中文文档 第二章 指南(4.8)添加新的字段
原文 Adding a New Field 作者 Rick Anderson 翻译 谢炀(Kiler) 校对 许登洋(Seay).高嵩(Jack) 在这个章节你将使用 Entity Framework ...
- 利用Python进行数据分析(4) NumPy基础: ndarray简单介绍
一.NumPy 是什么 NumPy 是 Python 科学计算的基础包,它专为进行严格的数字处理而产生.在之前的随笔里已有更加详细的介绍,这里不再赘述. 利用 Python 进行数据分析(一)简单介绍 ...
- SQL Server 中怎么查看一个字母的ascii编码或者Unicode编码
参考文章:微信公众号文章 在sql中怎么查看一个字符的ascii编码,so easy !! select ASCII('a') SELECT CHAR(97) charNum SELECT UNICO ...
- asp.net core 1.1 升级后,操作mysql出错的解决办法。
遇到问题 core的版本从1.0升级到1.1,操作mysql数据库,查询数据时遇到MissingMethodException问题,更新.插入操作没有问题. 如果你也遇到这个问题,请参照以下步骤进行升 ...
- bzoj1036--树链剖分
模板题... #include<iostream> #include<cstdio> #include<cstring> using namespace std; ...