您的位置:首页 > 编程语言 > Java开发

java 内存编译-动态编译

2012-08-24 16:15 267 查看
由我的文章/article/10104810.html中写的程序改写而成。

java底层是有内存编译类的:

javax.tools.JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler();

但是,他无法在自定义的ClassLoader下运行,比如说在Tomcat下运行的web项目,就无法使用这种方式进行动态编译,因为Tomcat为每一个web应用都分配了一个ClassLoader。

下面来看下我的代码吧,完成已经好久了,这是在真实项目开发过程中运行了很久以后我才贴出来的。

最下面是测试类。看吧没多少注释,应该能看懂,很简单的。

如果有问题请留言!

DCompilationUnit.java

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.StringTokenizer;

import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;

public class DCompilationUnit implements ICompilationUnit {

String className;
String sourceFile;
String javaEncoding;
String src;

DCompilationUnit(String sourceFile, String className, String javaEncoding, String src) {
this.className = className;
this.sourceFile = sourceFile;
this.javaEncoding = javaEncoding;
this.src = src;
}

public char[] getFileName() {
return sourceFile.toCharArray();
}

public char[] getContents() {
return src.toCharArray();
//        char[] result = null;
//        FileInputStream is = null;
//        try {
//            is = new FileInputStream(sourceFile);
//            Reader reader =
//                new BufferedReader(new InputStreamReader(is, javaEncoding));
//            if (reader != null) {
//                char[] chars = new char[8192];
//                StringBuffer buf = new StringBuffer();
//                int count;
//                while ((count = reader.read(chars, 0,
//                                            chars.length)) > 0) {
//                    buf.append(chars, 0, count);
//                }
//                result = new char[buf.length()];
//                buf.getChars(0, result.length, result, 0);
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        } finally {
//            if (is != null) {
//                try {
//                    is.close();
//                } catch (IOException exc) {
//                    // Ignore
//                }
//            }
//        }
//        return result;
}

public char[] getMainTypeName() {
int dot = className.lastIndexOf('.');
if (dot > 0) {
return className.substring(dot + 1).toCharArray();
}
return className.toCharArray();
}

public char[][] getPackageName() {
StringTokenizer izer =
new StringTokenizer(className, ".");
char[][] result = new char[izer.countTokens()-1][];
for (int i = 0; i < result.length; i++) {
String tok = izer.nextToken();
result[i] = tok.toCharArray();
}
return result;
}
}


DCompile.java

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;

import java.util.Locale;
import java.util.Map;
import java.util.HashMap;

import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;

public class DCompile {
private DCompileModel dm;

private Boolean init = false;

private ICompilationUnit[] compilationUnits = null;

public void compile() throws Exception {
if (!check()) {
throw new Exception("Not initialize...");
}
int length = dm.length();
compilationUnits = new ICompilationUnit[length];

for (int i = 0; i < length; i++) {
compilationUnits[i] = new DCompilationUnit(dm.getJfps(i),
dm.getJtfp(i), dm.encode(), dm.getSrc(i));
}
final DNameEnvironment env = new DNameEnvironment(dm);

final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies
.proceedWithAllProblems();

final DCompilerRequestor requestor = new DCompilerRequestor(dm);

final IProblemFactory problemFactory = new DefaultProblemFactory(Locale
.getDefault());

Compiler compiler = new Compiler(env, policy, getSettings(), requestor,
problemFactory, true);
compiler.compile(compilationUnits);

//打印完成信息...
finish();
}

public Map getSettings() {
Map settings = new HashMap();
settings.put(CompilerOptions.OPTION_LineNumberAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_SourceFileAttribute,
CompilerOptions.GENERATE);
settings.put(CompilerOptions.OPTION_ReportDeprecation,
CompilerOptions.IGNORE);

settings.put(CompilerOptions.OPTION_Encoding, dm.encode());

// Source JVM
settings
.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6);

// Target JVM
settings.put(CompilerOptions.OPTION_TargetPlatform,
CompilerOptions.VERSION_1_6);
settings.put(CompilerOptions.OPTION_Compliance,
CompilerOptions.VERSION_1_6);
return settings;
}

private boolean check() {
return init;
}

public DCompile() {
}

public void initialize(DCompileModel dm) {
this.dm = dm;

//移除所有class文件
//		removeClassFile();
//		System.out.println("remove old class file......");

init = true;
}

private void removeClassFile(){
int length = dm.length();
File f = null;
for (int i = 0; i < length; i++) {
f = new File(dm.getJfps(i).replace(".java", ".class"));
if(f.exists()){
f.delete();
}
}
}

public void delAll(File f) throws IOException {

if(!f.exists()){
return;
}

boolean rslt=true;
if(!(rslt=f.delete())){
File subs[] = f.listFiles();
for (int i = 0; i <= subs.length - 1; i++) {
if (subs[i].isDirectory())
delAll(subs[i]);
rslt = subs[i].delete();
}
rslt = f.delete();
}

if(!rslt){
throw new IOException("无法删除:"+f.getName());
}
return;
}

private void finish(){
int length = dm.length();
//		for (int i = 0; i < length; i++) {
//			System.out.println(dm.getJfps(i));
//		}
System.out.println("<compile>...finish DCompile.size=" + length);
}
}


DCompileModelDCompileModel.java

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

public class DCompileModel {
private DURLClassLoader ucl;
/* 文件路径 */
private ArrayList<String> jfps = new ArrayList<String>();
/* 类名 */
private ArrayList<String> jtfp = new ArrayList<String>();
/* 引用jar文件名 */
private ArrayList<String> jars = new ArrayList<String>();
/* 源文件 */
private ArrayList<String> srcs = new ArrayList<String>();
/* 类源文件 */
private ArrayList<byte[]> clazzs = new ArrayList<byte[]>();
private String java_basic_path;
private ClassLoader classLoader;
private String encode;

private boolean size_old = false;
private int length = 0;

public void refresh(){
jfps.clear();
jtfp.clear();
jars.clear();
srcs.clear();
clazzs.clear();
}

public void constructClassLoader() throws MalformedURLException{
int jar_length = jars.size();
URL[] urls = new URL[jar_length +1];
urls[0] = new URL("file:/" + java_basic_path + "/");
for(int i=1; i<urls.length; i++){
urls[i] = new java.io.File(jars.get(i-1)).toURL();
}
ucl = new DURLClassLoader(urls, classLoader);
ucl.addDCompileModel(this);
}

public void removeClassFile(){
int length = this.length();
File f = null;
for (int i = 0; i < length; i++) {
f = new File(this.getJfps(i).replace(".java", ".class"));
if(f.exists()){
f.delete();
}
}
}

public DCompileModel(String java_basic_path, String encode,ClassLoader classLoader){
this.java_basic_path = java_basic_path;
this.classLoader = classLoader;
this.encode = encode;
}

private String getTargetClassName(String java_file_path) {
String targetClassName = java_file_path.substring(
java_basic_path.length() + 1, java_file_path.indexOf(".java"));
return targetClassName.replace("/", ".");
}

public void addFilePath(String java_file_path, String src){
jfps.add(java_file_path);
srcs.add(src);
jtfp.add(getTargetClassName(java_file_path));
size_old = true;
}

public void addClass(int index, byte[] clazz){
clazzs.add(index, clazz);
}
public byte[] getClass(int index){
return clazzs.get(index);
}

public void addJarPath(String jarp){
jars.add(jarp);
}

public String getJarPath(int index){
return jars.get(index);
}

public ArrayList<String> getJarPathList(){
return jars;
}

public URLClassLoader classLoader(){
return this.ucl;
}

public String getBasicPath(){
return this.java_basic_path;
}

public String encode(){
return this.encode;
}

public ArrayList<String> getFileList(){
return this.jfps;
}

public ArrayList<String> getTargetClassList(){
return this.jtfp;
}

public String getJfps(int index){
return jfps.get(index);
}

public boolean containsJfps(Object o){
return jfps.contains(o);
}

public String getJtfp(int index){
return jtfp.get(index);
}

public boolean containsJtfp(Object o){
return jtfp.contains(o);
}

public String getSrc(int index){
return srcs.get(index);
}

public int length(){
if(size_old){
length = jfps.size();
size_old = false;
}
return length;
}

}


DCompilerRequestor.java

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;

import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ClassFile;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;

public class DCompilerRequestor implements ICompilerRequestor{

private String outputDir;
private DCompileModel dm;

public DCompilerRequestor(DCompileModel dm){
this.dm = dm;
this.outputDir = dm.getBasicPath();
}

public void acceptResult(CompilationResult result) {
try {
boolean error = false;
if (result.hasProblems()) {
IProblem[] problems = result.getProblems();
for (int i = 0; i < problems.length; i++) {
IProblem problem = problems[i];
if (problem.isError()) {
error = true;
StringBuffer errSb = new StringBuffer();
errSb.append(problem.getOriginatingFileName());
errSb.append("\r\n");
errSb.append(problem.toString());
System.err.println(errSb.toString());
}
}
}
if (!error) {
ClassFile[] classFiles = result.getClassFiles();
for (int i = 0; i < classFiles.length; i++) {
ClassFile classFile = classFiles[i];
char[][] compoundName =
classFile.getCompoundName();
String className = "";
String sep = "";
for (int j = 0;
j < compoundName.length; j++) {
className += sep;
className += new String(compoundName[j]);
sep = ".";
}
byte[] bytes = classFile.getBytes();
ArrayList<String> list = dm.getTargetClassList();
int index = list.indexOf(className);
dm.addClass(index, bytes);

//                    String outFile = outputDir + "/" +
//                        className.replace('.', '/') + ".class";
//
//                    File file = new File(new File(outFile).getParent());
//                    if(!file.exists()){
//                    	file.mkdirs();
//                    }
//
//                    FileOutputStream fout =
//                        new FileOutputStream(outFile);
//                    BufferedOutputStream bos =
//                        new BufferedOutputStream(fout);
//                    bos.write(bytes);
//                    bos.close();
}
}
} catch (Exception exc) {
exc.printStackTrace();
}
}
}


DNameEnvironment.java

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;

public class DNameEnvironment implements INameEnvironment {

private ClassLoader classLoader;
private String encode;
private DCompileModel dm;

public DNameEnvironment(DCompileModel dm){
this.classLoader = dm.classLoader();
this.encode = dm.encode();
this.dm = dm;
}

public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
String result = "";
String sep = "";
for (int i = 0; i < compoundTypeName.length; i++) {
result += sep;
result += new String(compoundTypeName[i]);
sep = ".";
}
return findType(result);
}

public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
String result = "";
String sep = "";
for (int i = 0; i < packageName.length; i++) {
result += sep;
result += new String(packageName[i]);
sep = ".";
}
result += sep;
result += new String(typeName);
return findType(result);
}

private NameEnvironmentAnswer findType(String className) {
//		System.out.println(">>>>>>>>>>>>" + className);
InputStream is = null;
try {
int length = dm.length();
for (int i = 0; i < length; i++) {
if (className.equals(dm.getJtfp(i))) {
ICompilationUnit compilationUnit = new DCompilationUnit(
dm.getJfps(i), className, encode, dm.getSrc(i));
return new NameEnvironmentAnswer(compilationUnit, null);
}
}

String resourceName = className.replace('.', '/') + ".class";
is = classLoader.getResourceAsStream(resourceName);
if (is != null) {
byte[] classBytes;
byte[] buf = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream(
buf.length);
int count;
while ((count = is.read(buf, 0, buf.length)) > 0) {
baos.write(buf, 0, count);
}
baos.flush();
classBytes = baos.toByteArray();
char[] fileName = className.toCharArray();
ClassFileReader classFileReader = new ClassFileReader(
classBytes, fileName, true);
return new NameEnvironmentAnswer(classFileReader, null);
}
} catch (IOException exc) {
exc.printStackTrace();
} catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
exc.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException exc) {
// Ignore
}
}
}
return null;
}

private boolean isPackage(String result) {
if (dm.containsJtfp(result)) {
return false;
}
String resourceName = result.replace('.', '/') + ".class";
InputStream is = classLoader.getResourceAsStream(resourceName);
return is == null;
}

public boolean isPackage(char[][] parentPackageName, char[] packageName) {
String result = "";
String sep = "";
if (parentPackageName != null) {
for (int i = 0; i < parentPackageName.length; i++) {
result += sep;
String str = new String(parentPackageName[i]);
result += str;
sep = ".";
}
}
String str = new String(packageName);
if (Character.isUpperCase(str.charAt(0))) {
if (!isPackage(result)) {
return false;
}
}
result += sep;
result += str;
return isPackage(result);
}

public void cleanup() {
}

}


DURLClassLoader.java

import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

public class DURLClassLoader extends URLClassLoader{

private DCompileModel dm;

public DURLClassLoader(URL[] urls) {
super(urls);
}

public DURLClassLoader(URL[] urls, ClassLoader parent){
super(urls,parent);
}

public void addDCompileModel(DCompileModel dm){
this.dm = dm;
}

public Class<?> loadClass(String name) throws ClassNotFoundException {
Class c = super.loadClass(name);
if(c != null){
return c;
}
return this.findClass(name);

}

@Override
protected Class<?> findClass(String name)
throws ClassNotFoundException {
try{
Class c = super.findClass(name);
if(c != null){
return c;
}
}catch(java.lang.ClassNotFoundException cnfe){

}
ArrayList<String> list = dm.getTargetClassList();
int index = list.indexOf(name);
byte[] b = dm.getClass(index);
return super.defineClass(name, b, 0,
b.length);
}

}


TestCompileInMemory2.java

import com.dynamic.DDynamicCompile;
import com.dynamic.DynamicCompileConfig;

public class TestCompileInMemory2 {
private static DDynamicCompile compile = null;
public static void main(String[] args) {
DynamicCompileConfig dynamicConfig = new DynamicCompileConfig();
dynamicConfig.setJava_basic_path("/");
dynamicConfig.setJar_basic_path("/");
dynamicConfig.setEncode("utf8");
compile = new DDynamicCompile(dynamicConfig);

//刷新内存
compile.refreshCompileModel();

StringBuffer sb = new StringBuffer();
sb.append("package com.dbdxj.test;\n");
sb.append("public class Rock{\n");
sb.append("	public String toString(){\n");
sb.append("		return \"测试程序\";\n");
sb.append("	}\n");
sb.append("}\n");

try {
Object obj = compile("com.dbdxj.test.Rock", sb.toString());
System.out.println(obj);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public static <T> T compile(String classFullName, String src) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
compile.addFilePath(classFullName + ".java", src);
compile.compile();

return (T)compile.loadClassObj(classFullName);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: