首页 > 代码库 > java动态编译类文件并加载到内存中

java动态编译类文件并加载到内存中

  如果你想在动态编译并加载了class后,能够用hibernate的数据访问接口以面向对象的方式来操作该class类,请参考笔者的这篇博文-(该博文暂未发布)

  所谓动态编译,就是在程序运行时产生java类,并编译成class文件。  

  一、这里介绍两种动态编译java文件的方式。

    第一种:使用Runtime执行javac命令

技术分享
/**     * 编译java类     * 使用Runtime执行javac命令     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @throws java.io.IOException     */    public static void javac(String name) throws IOException {        String javaPackageName = name.replace(".",File.separator)+".java";        String javaAbsolutePath = classPath+javaPackageName;        Process process = Runtime.getRuntime().exec("javac -classpath "+ jarAbsolutePath+ " " + javaAbsolutePath);        try {            InputStream errorStream = process.getErrorStream();            InputStreamReader inputStreamReader = new InputStreamReader(errorStream);            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);            String line = null;            while ((line=bufferedReader.readLine()) != null){                System.out.println(line);            }            int exitVal = process.waitFor();            System.out.println("Process exitValue: " + exitVal);        } catch (InterruptedException e) {            e.printStackTrace();        }    }
View Code

    第二种:使用jdk自带的rt.jar中的javax.tools包提供的编译器

技术分享
/**     * 编译java类     * 使用rt.jar中的javax.tools包提供的编译器     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @throws java.io.IOException     */    public static void compiler(String name) throws IOException {        String javaPackageName = name.replace(".",File.separator)+".java";        String javaAbsolutePath = classPath+javaPackageName;        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();        compiler.run(null,null,null,"-encoding","UTF-8","-classpath",jarAbsolutePath.toString(),javaAbsolutePath);    }
View Code

  二、使用Class.forName("");将class文件加载到内存中,并得到该类的class对象

技术分享
/**     * 动态编译一个java源文件并加载编译生成的class     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @throws java.io.IOException     */    public static Class<?> dynamicLoadClass(String name) throws IOException, ClassNotFoundException {        if (!isClassExist(name)){            compiler(name);        }        if(isJavaExist(name)){            if(!FileUtil.destroyFile(classPath + name.replace(".",File.separator)+".java")){                System.out.println("========================================>>>>删除源文件失败!");            }        }        return Class.forName(name);    }
View Code

  以下是全部代码:

技术分享
package com.basic.core.classloader;import com.basic.core.util.FileUtil;import sun.tools.jar.Main;import javax.tools.JavaCompiler;import javax.tools.ToolProvider;import java.io.*;import java.nio.file.Files;import java.nio.file.Paths;/** * desc:自定义的类加载器,用于实现类的动态加载 */public class MyClassLoader extends ClassLoader {    //类路径    private static String classPath ;    private static String jarPrefix;    private static StringBuilder jarAbsolutePath;    static{        classPath = MyClassLoader.class.getClassLoader().getResource("").getPath();        classPath = !classPath.startsWith("/")?classPath:classPath.substring(1);//去掉开始位置的/        classPath = classPath.endsWith(File.separator)?classPath:classPath+File.separator;        jarPrefix = classPath.substring(0,classPath.lastIndexOf("classes"))+File.separator+"lib"+File.separator;        jarAbsolutePath = new StringBuilder().append(jarPrefix)                .append("hibernate-core-4.2.0.Final.jar;")                .append(jarPrefix).append("hibernate-jpa-2.0-api-1.0.1.Final.jar;")                .append(jarPrefix).append("validation-api-1.0.0.GA.jar;");    }    /**     * 如果父的类加载器中都找不到name指定的类,     * 就会调用这个方法去从磁盘上加载一个类     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @return     * @throws java.io.IOException     */    @Override    protected Class<?> findClass(String name) throws ClassNotFoundException {        byte[] classBytes = null;        Class<?> clazz = null;        try {            //加载类的字节码            classBytes = loadClassBytes(name);            //将字节码交给JVM            clazz = defineClass(name,classBytes,0,classBytes.length);            if(clazz == null){                throw new ClassNotFoundException(name);            }        } catch (IOException e) {            e.printStackTrace();        }        return clazz;    }    /**     * 加载类的字节码     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @return     * @throws java.io.IOException     */    private byte[] loadClassBytes(String name) throws IOException {        String classPackageName = name.replace(".",File.separator)+".class";        String classAbsolutePath = classPath+classPackageName;        //编译java文件        javac(name);        byte[] bytes = Files.readAllBytes(Paths.get(classAbsolutePath));        return bytes;    }    /**     * 指定的类的class是否存在     * @param name     * @return     * @throws IOException     */    public static boolean isClassExist(String name) throws IOException {        String classPackageName = name.replace(".",File.separator)+".class";        return FileUtil.isExists(classPath+classPackageName)?true:false;    }    /**     * 指定的类是否存在     * @param name     * @return     * @throws IOException     */    public static boolean isJavaExist(String name) throws IOException {        String classPackageName = name.replace(".",File.separator)+".java";        return FileUtil.isExists(classPath+classPackageName)?true:false;    }    /**     * 编译java类     * 使用Runtime执行javac命令     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @throws java.io.IOException     */    public static void javac(String name) throws IOException {        String javaPackageName = name.replace(".",File.separator)+".java";        String javaAbsolutePath = classPath+javaPackageName;        Process process = Runtime.getRuntime().exec("javac -classpath "+ jarAbsolutePath+ " " + javaAbsolutePath);        try {            InputStream errorStream = process.getErrorStream();            InputStreamReader inputStreamReader = new InputStreamReader(errorStream);            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);            String line = null;            while ((line=bufferedReader.readLine()) != null){                System.out.println(line);            }            int exitVal = process.waitFor();            System.out.println("Process exitValue: " + exitVal);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    /**     * 编译java类     * 使用rt.jar中的javax.tools包提供的编译器     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @throws java.io.IOException     */    public static void compiler(String name) throws IOException {        String javaPackageName = name.replace(".",File.separator)+".java";        String javaAbsolutePath = classPath+javaPackageName;        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();        compiler.run(null,null,null,"-encoding","UTF-8","-classpath",jarAbsolutePath.toString(),javaAbsolutePath);    }    /**     * 动态编译一个java源文件并加载编译生成的class     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java     * @throws java.io.IOException     */    public static Class<?> dynamicLoadClass(String name) throws IOException, ClassNotFoundException {        if (!isClassExist(name)){            compiler(name);        }        if(isJavaExist(name)){            if(!FileUtil.destroyFile(classPath + name.replace(".",File.separator)+".java")){                System.out.println("========================================>>>>删除源文件失败!");            }        }        return Class.forName(name);    }    public static void main (String[] args){            }}
View Code

  

 

java动态编译类文件并加载到内存中