不多说直接上代码:

动态编译的主类:

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. Docker数据持久化与容器迁移

    上节讲到当容器运行期间产生的数据是不会在写镜像里面的,重新用此镜像启动新的容器就会初始化镜像,会加一个全新的读写入层来保存数据.如果想做到数据持久化,Docker提供数据卷(Data volume)或 ...

  2. zabbix注入过程分析

    Zabbix jsrpc.php sql 注入过程分析 漏洞公开详情(https://support.zabbix.com/browse/ZBX-11023)中提示在insertDB() 中的inse ...

  3. Symbiont

    http://www.weiyangx.com/209230.html Symbiont,Credit Suisse与R3携手革新贷款数据验证环节Symbiont, Credit Suisse and ...

  4. Android ViewPager sharedpreferences

    http://www.cnblogs.com/dwinter/archive/2012/02/27/AndroidViewPager%E5%A4%9A%E9%A1%B5%E9%9D%A2%E6%BB% ...

  5. codevs1183 泥泞的道路

    题目描述 Description CS有n个小区,并且任意小区之间都有两条单向道路(a到b,b到a)相连.因为最近下了很多暴雨,很多道路都被淹了,不同的道路泥泞程度不同.小A经过对近期天气和地形的科学 ...

  6. 只用@property定义一个属性speed,子类不能直接用_speed,需要在interface的成员变量列表里写上_speed

    //写法一: @interface Person : NSObject { } @property (nonatomic, strong) NSString *name; @end @implemen ...

  7. Swift3.0P1 语法指南——类和结构体

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

  8. espcms会员二次开发文件说明——会员,时间格式

    [espcms会员图片字段] 添加字段加入图片类型/webadm/include/inc_formtypelist.php 会员修改页面模型/webadm/templates/member/membe ...

  9. 无阻塞加载js,防止因js加载不了影响页面显示

    浏览器加载静态资源和js的方式都是线性加载,所以一般情况可以将js放到</body>前,防止UI线程的阻塞. 而某些时候我们既希望js在整个网页的头部就加载,又担心js阻塞导致网站加载缓慢 ...

  10. 创建 WPF 工具箱控件

    创建 WPF 工具箱控件 WPF (Windows Presentation Framework) 工具箱控件模板允许您创建 WPF 控件,会自动添加到 工具箱 安装扩展的安装. 本主题演示如何使用模 ...