不多说直接上代码:

动态编译的主类:

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_动态编译总结的更多相关文章

  1. (转载)JAVA动态编译--字节代码的操纵

    在一般的Java应用开发过程中,开发人员使用Java的方式比较简单.打开惯用的IDE,编写Java源代码,再利用IDE提供的功能直接运行Java 程序就可以了.这种开发模式背后的过程是:开发人员编写的 ...

  2. ZKWeb网站框架的动态编译的实现原理

    ZKWeb网站框架是一个自主开发的网页框架,实现了动态插件和自动编译功能. ZKWeb把一个文件夹当成是一个插件,无需使用csproj或xproj等形式的项目文件管理,并且支持修改插件代码后自动重新编 ...

  3. java动态编译笔记

    1 前言 Java的动态编译知识,真真在实际开发中并不是经常遇到.但是学习java动态编译有助于我们从更深一层次去了解java.对掌握jdk的动态代理模式,这样我们在学习其他一些开源框架的时候就能够知 ...

  4. c#动态编译并动态生成dll

    /// <summary> /// 动态编译并执行代码 /// </summary> /// <param name="code">代码< ...

  5. Java动态编译

    程序产生过程 下图展示了从源代码到可运行程序的过程,正常情况下先编译(明文源码到字节码),后执行(JVM加载字节码,获得类模板,实例化,方法使用).本文来探索下当程序已经开始执行,但在.class甚至 ...

  6. 重写代码生成器支持模板(多层架构,MVC),多语言c#,java;支持mysql和sqlserver,动态编译

    多年前用过李天平前辈的,自己改过,后来李老师做动软了,不给源码,修改不是很方便.加上我目前需要转java方向,于是决定自己搞.到目前为止花了整整一个星期了,看看目前的成果. 最后是代码工程文件,用c# ...

  7. 浅谈VB.Net 程序的编译和动态编译

    ---恢复内容开始--- 一般,我们都是通过Visual Studio(下面简称vs)来编写和编译vb.net应用程序的,但是,不少的人并不知道vs是通过何种方式编译程序的.今天,我们就来探讨一下编译 ...

  8. .NET中的动态编译

    代码的动态编译并执行是一个.NET平台提供给我们的很强大的工具用以灵活扩展(当然是面对内部开发人员)复杂而无法估算的逻辑,并通过一些额外的代码来扩展我们已有 的应用程序.这在很大程度上给我们提供了另外 ...

  9. C#动态编译代码,执行一个代码片段,或者从指定文件中加载某个接口的实现类

    在项目进行中有时候会需要配置一些复杂的表达式,在程序运行的时候执行表达式,根据结果执行相应的操作,简单写了一个类Expression,利用.net的动态编译技术实现,代码如下: public clas ...

随机推荐

  1. SearchLookUpEdit

    参考资料: 慧都控件网-DevExpress开发资源 在GridControl控件中使用SearchLookUpEdit构建数据快速输入

  2. R的卸载和更新安装

      R包经常会遇到各种版本不兼容的毛病,比如当前的版本相较于包,新了/旧了都是麻烦 而升级R软件呢,最麻烦的就是之前安装的包怎么办? 搜罗了以下几种方法:   方法1: (1)直接安装新版本 (2)然 ...

  3. tyvj1193 括号序列

    描述 定义如下规则序列(字符串):1.空序列是规则序列:2.如果S是规则序列,那么(S)和[S]也是规则序列:3.如果A和B都是规则序列,那么AB也是规则序列.       例如,下面的字符串都是规则 ...

  4. jQuery入门(3)事件与事件对象

    jQuery入门(1)jQuery中万能的选择器 jQuery入门(2)使用jQuery操作元素的属性与样式 jQuery入门(3)事件与事件对象 jQuery入门(4)jQuery中的Ajax()应 ...

  5. Swift3.0P1 语法指南——属性

    原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...

  6. 第3月第9天 循环引用 block

    一.一个对象没有被引用,那么在函数块完成时就会被dealloc,这种情况因为对象销毁了,block块也永远不会执行. MyNetworkOperation *op = [[MyNetworkOpera ...

  7. 用vuejs实现一个todolist项目

    用vue.js实现一个todolist项目:input输入框输入的值会呈现在下方,并且会保存在localStorage里面,而且下方的列表点击之后也会有变化: 完整代码: App.vue <te ...

  8. 使用http.sys,让delphi 的多层服务飞起来

    核心提示:一直以来,delphi 的网络通讯层都是以indy 为主,虽然indy 的功能非常多,涉及到网络服务的各个方面,但是对于大多数多层服务来说,就是需要一个快速.稳定.高效的传输层.Delphi ...

  9. windows系统和ubuntu虚拟机之间文件共享——samba

    参考:http://www.cnblogs.com/phinecos/archive/2009/06/06/1497717.html 一. samba的安装: sudo apt-get insall  ...

  10. webstrom配置sass与less

    1.less 安装一个稳定版的node.[例如node-v4.4.4-x64] 然后直接在webstrom里导入那个lessc.cmd 2.sass 安装ruby. 安装完之后点开,Start那个安装 ...