Java_动态编译总结
不多说直接上代码:
动态编译的主类:
package com.lkb.autoCode.util; import com.lkb.autoCode.constant.AutoCodeConstant;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import javax.tools.*;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; /**
* AutoCompiler 动态编译器
*
* @author Lilin
* @date 2016/5/18
*/
public class AutoCompiler {
private static final Log log = LogFactory.getLog(AutoCompiler.class); /**
* Description: Compile java source file to java class with run method
*
* @param fullFileName the java source file name with full path
* @return true-compile successfully, false - compile unsuccessfully
*/
public static boolean compileFile(String fullFileName) {
boolean bRet = false;
// get compiler
JavaCompiler oJavaCompiler = ToolProvider.getSystemJavaCompiler();
// compile the java source code by run method
int iCompileRet = oJavaCompiler.run(null, null, null, fullFileName);
// set compile result
if (0 == iCompileRet) {
bRet = true;
}
return bRet;
} /**
* Description: Compile java source file to java class with getTask
* method, it can specify the class output path and catch diagnostic
* information
*
* @param fullFileName the java source file name with full path
* @param outputPath the output path of java class file
* @return true-compile successfully, false - compile unsuccessfully
* @throws IOException
*/
public static boolean compileFile(String fullFileName, String outputPath) {
System.out.println("源文件路径:" + fullFileName);
System.out.println("输入路径:" + outputPath);
boolean bRet = false;
// get compiler
// TODO 当运行环境是JRE是无法直接ToolProvider.getSystemJavaCompiler();这么获取
JavaCompiler oJavaCompiler = ToolProvider.getSystemJavaCompiler(); // define the diagnostic object, which will be used to save the diagnostic information
DiagnosticCollector<JavaFileObject> oDiagnosticCollector = new DiagnosticCollector<JavaFileObject>(); // get StandardJavaFileManager object, and set the diagnostic for the object
StandardJavaFileManager oStandardJavaFileManager = oJavaCompiler
.getStandardFileManager(oDiagnosticCollector, null, null); // set class output location
JavaFileManager.Location oLocation = StandardLocation.CLASS_OUTPUT;
try {
File outputFile = new File(outputPath);
if (!outputFile.exists()) {
outputFile.mkdir();
}
List<File> dependencies = new ArrayList<File>(); // 加载依赖的jar文件
dependencies.addAll(getJarFiles(AutoCodeConstant.JARS_PATH));
// 加载依赖的class文件
dependencies.add(new File(AutoCodeConstant.BASE_PATH)); oStandardJavaFileManager.setLocation(StandardLocation.CLASS_PATH, dependencies);
oStandardJavaFileManager.setLocation(oLocation, Arrays
.asList(new File[]{outputFile})); File sourceFile = new File(fullFileName);
// get JavaFileObject object, it will specify the java source file.
Iterable<? extends JavaFileObject> oItJavaFileObject = oStandardJavaFileManager
.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile));
// -g 生成所有调试信息
// -g:none 不生成任何调试信息
// -g:{lines,vars,source} 只生成某些调试信息
// -nowarn 不生成任何警告
// -verbose 输出有关编译器正在执行的操作的消息
// -deprecation 输出使用已过时的 API 的源位置
// -classpath <路径> 指定查找用户类文件的位置
// -cp <路径> 指定查找用户类文件的位置
// -sourcepath <路径> 指定查找输入源文件的位置
// -bootclasspath <路径> 覆盖引导类文件的位置
// -extdirs <目录> 覆盖安装的扩展目录的位置
// -endorseddirs <目录> 覆盖签名的标准路径的位置
// -d <目录> 指定存放生成的类文件的位置
// -encoding <编码> 指定源文件使用的字符编码
// -source <版本> 提供与指定版本的源兼容性
// -target <版本> 生成特定 VM 版本的类文件
// -version 版本信息
// -help 输出标准选项的提要
// -X 输出非标准选项的提要
// -J<标志> 直接将 <标志> 传递给运行时系统 // 编译选项,将编译产生的类文件放在当前目录下
//Iterable<String> options = Arrays.asList("-encoding", AutoCodeConstant.CONTENT_ENCODING, "-classpath", getJarFiles(AutoCodeConstant.JARS_PATH));
Iterable<String> options = Arrays.asList("-encoding", AutoCodeConstant.CONTENT_ENCODING);
// compile the java source code by using CompilationTask's call method
bRet = oJavaCompiler.getTask(null, oStandardJavaFileManager,
oDiagnosticCollector, options, null, oItJavaFileObject).call(); //print the Diagnostic's information
for (Diagnostic oDiagnostic : oDiagnosticCollector
.getDiagnostics()) {
// log.info("Error on line: "
// + oDiagnostic.getLineNumber() + "; URI: "
// + oDiagnostic.getSource().toString());
System.out.printf(
"Code: %s%n" +
"Kind: %s%n" +
"Position: %s%n" +
"Start Position: %s%n" +
"End Position: %s%n" +
"Source: %s%n" +
"Message: %s%n",
oDiagnostic.getCode(), oDiagnostic.getKind(),
oDiagnostic.getPosition(), oDiagnostic.getStartPosition(),
oDiagnostic.getEndPosition(), oDiagnostic.getSource(),
oDiagnostic.getMessage(null));
}
} catch (IOException e) {
log.error("动态编译出现异常", e);
} finally {
//close file manager
if (null != oStandardJavaFileManager) {
try {
oStandardJavaFileManager.close();
} catch (IOException e) {
e.printStackTrace();
log.error("动态编译关闭文件管理器出现异常", e);
}
}
}
return bRet;
} /**
* 查找该目录下的所有的jar文件
*
* @param jarPath
* @throws Exception
*/
private static List<File> getJarFiles(String jarPath) {
final List<File> dependencyJars = new ArrayList<File>();
File sourceFile = new File(jarPath);
if (sourceFile.exists()) {// 文件或者目录必须存在
if (sourceFile.isDirectory()) {// 若file对象为目录
// 得到该目录下以.java结尾的文件或者目录
File[] childrenFiles = sourceFile.listFiles(new FileFilter() {
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
return true;
} else {
String name = pathname.getName();
if (name.endsWith(".jar") ? true : false) {
//jars[0] = jars[0] + pathname.getPath() + ";";
dependencyJars.add(pathname);
return true;
}
return false;
}
}
});
}
}
return dependencyJars;
}
}
辅助类:
package com.lkb.autoCode.constant; /**
* AutoCodeConstant
*
* @author Lilin
* @date 2016/5/18
*/
public class AutoCodeConstant {
/**
* 登录模板名称
*/
public static String LOGIN_TEMPLATE_FTL = "LoginClientTemplate.ftl";
/**
* 项目根路径
*/
public final static String BASE_PATH = AutoCodeConstant.class.getResource("/").toString().replaceAll("^file:/", ""); /**
* Jar包所在目录
*/
public final static String JARS_PATH = BASE_PATH.replace("classes","lib");
/**
* 模板根路径
*/
public final static String BASE_TEMPLATE_PATH = BASE_PATH + "template";
/**
* client目录
*/
public final static String LOCAL_CLIENT_BASE_PATH = "src/main/java/com/lkb/sb/client/";
/**
* client目录
*/
public final static String CLIENT_BASE_PATH = "com/lkb/sb/client/";
/**
* client类名后缀
*/
public final static String LOGIN_CLIENT_SUFFIX = "LoginClient.java";
/**
* 默认编译输出路径
*/
public final static String DEFULT_OUTPUT_PATH = "/";
/**
* 编码格式
*/
public final static String CONTENT_ENCODING = "UTF-8"; }
开发背景:需求是根据代码模板动态生成java代码,并动态编译
开发过程中遇到的阻塞:模板代码中有依赖别的class文件和jar文件无法加载的问题
解决方法:
// 加载依赖的jar文件
dependencies.addAll(getJarFiles("jar文件的根路径"));
// 加载依赖的class文件
dependencies.add(new File("class文件的根路径")); /**
* 查找该目录下的所有的jar文件
*
* @param jarPath
* @throws Exception
*/
private static List<File> getJarFiles(String jarPath) {
final List<File> dependencyJars = new ArrayList<File>();
File sourceFile = new File(jarPath);
if (sourceFile.exists()) {// 文件或者目录必须存在
if (sourceFile.isDirectory()) {// 若file对象为目录
// 得到该目录下以.java结尾的文件或者目录
File[] childrenFiles = sourceFile.listFiles(new FileFilter() {
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
return true;
} else {
String name = pathname.getName();
if (name.endsWith(".jar") ? true : false) {
//jars[0] = jars[0] + pathname.getPath() + ";";
dependencyJars.add(pathname);
return true;
}
return false;
}
}
});
}
}
return dependencyJars;
}
Java_动态编译总结的更多相关文章
- (转载)JAVA动态编译--字节代码的操纵
在一般的Java应用开发过程中,开发人员使用Java的方式比较简单.打开惯用的IDE,编写Java源代码,再利用IDE提供的功能直接运行Java 程序就可以了.这种开发模式背后的过程是:开发人员编写的 ...
- ZKWeb网站框架的动态编译的实现原理
ZKWeb网站框架是一个自主开发的网页框架,实现了动态插件和自动编译功能. ZKWeb把一个文件夹当成是一个插件,无需使用csproj或xproj等形式的项目文件管理,并且支持修改插件代码后自动重新编 ...
- java动态编译笔记
1 前言 Java的动态编译知识,真真在实际开发中并不是经常遇到.但是学习java动态编译有助于我们从更深一层次去了解java.对掌握jdk的动态代理模式,这样我们在学习其他一些开源框架的时候就能够知 ...
- c#动态编译并动态生成dll
/// <summary> /// 动态编译并执行代码 /// </summary> /// <param name="code">代码< ...
- Java动态编译
程序产生过程 下图展示了从源代码到可运行程序的过程,正常情况下先编译(明文源码到字节码),后执行(JVM加载字节码,获得类模板,实例化,方法使用).本文来探索下当程序已经开始执行,但在.class甚至 ...
- 重写代码生成器支持模板(多层架构,MVC),多语言c#,java;支持mysql和sqlserver,动态编译
多年前用过李天平前辈的,自己改过,后来李老师做动软了,不给源码,修改不是很方便.加上我目前需要转java方向,于是决定自己搞.到目前为止花了整整一个星期了,看看目前的成果. 最后是代码工程文件,用c# ...
- 浅谈VB.Net 程序的编译和动态编译
---恢复内容开始--- 一般,我们都是通过Visual Studio(下面简称vs)来编写和编译vb.net应用程序的,但是,不少的人并不知道vs是通过何种方式编译程序的.今天,我们就来探讨一下编译 ...
- .NET中的动态编译
代码的动态编译并执行是一个.NET平台提供给我们的很强大的工具用以灵活扩展(当然是面对内部开发人员)复杂而无法估算的逻辑,并通过一些额外的代码来扩展我们已有 的应用程序.这在很大程度上给我们提供了另外 ...
- C#动态编译代码,执行一个代码片段,或者从指定文件中加载某个接口的实现类
在项目进行中有时候会需要配置一些复杂的表达式,在程序运行的时候执行表达式,根据结果执行相应的操作,简单写了一个类Expression,利用.net的动态编译技术实现,代码如下: public clas ...
随机推荐
- CSS3实现阴阳鱼
直接上代码: <!doctype html> <html> <head> <meta charset="utf-8" /> < ...
- Html限制input输入框只能输入数字
限制输入框只能输入数字, onafterpaste防止用户从其它地方copy内容粘贴到输入框: <input type="text" onkeyup="this.v ...
- Digital calculation
No1=1 No2=2 1. let result=No1+No2 let No1++ let No1+=3 2. result=$[No1+No2] 3. result=$((No1+No ...
- vijos1404 遭遇战
描述 今天,他们在打一张叫DUSTII的地图,万恶的恐怖分子要炸掉藏在A区的SQC论坛服务器!我们SQC的人誓死不屈,即将于恐怖分子展开激战,准备让一个人守着A区,这样恐怖分子就不能炸掉服务器了.(一 ...
- Unix目录结构的来历
作者: 阮一峰 Unix(包含Linux)的初学者,常常会很困惑,不明白目录结构的含义何在. 举例来说,根目录下面有一个子目录/bin,用于存放二进制程序.但是,/usr子目录下面还有/usr/bin ...
- Linux/CentOS 服务安装/卸载,开机启动chkconfig命令详解|如何让MySQL、Apache开机启动?
chkconfig chkconfig在命令行操作时会经常用到.它可以方便地设置和查询不同运行级上的系统服务.这个可要好好掌握,用熟练之后,就可以轻轻松松的管理好你的启动服务了. 注:谨记chkcon ...
- Mybatis在insert操作时返回主键
今天在写项目的时候,遇到一个需求,就是在像数据库插入数据的时候,要保留插入数据的主键,以便后续进行级联时,可以将该主键作为另张表的外键. 但是在正常情况下我们使用插入语句返回的是int型,含义是影响该 ...
- [转]spring beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- C# Bitmap deep copy
今天在研究一个关于 Bitmap deep copy 的问题, 经过一系列的查询,在StackOverFlow上面找到了答案,遂记录下来: public static Bitmap DeepCopyB ...
- Andorid实现点击获取验证码倒计时效果
这篇文章主要介绍了Andorid实现点击获取验证码倒计时效果,这种效果大家经常遇到,想知道如何实现的,请阅读本文 我们在开发中经常用到倒计时的功能,比如发送验证码后,倒计时60s再进行验证码的获取 ...