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

  如果你想在动态编译并加载了class后,能够用hibernate的数据访问接口以面向对象的方式来操作该class类,请参考这篇博文-http://www.cnblogs.com/anai/p/4270214.html

  所谓动态编译,就是在程序运行时产生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

  

 

posted @ 2015-02-03 14:15  程序员一一涤生  阅读(12422)  评论(0编辑  收藏  举报