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

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM