现在的位置: 首页 > 综合 > 正文

java 内存编译-动态编译

2013年01月22日 ⁄ 综合 ⁄ 共 13923字 ⁄ 字号 评论关闭

由我的文章http://blog.csdn.net/jl19861101/article/details/5450732中写的程序改写而成。

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);
	}
}

 

抱歉!评论已关闭.