天天看點

Java動态編譯和類的重新加載

注意:

1.動态編譯的class檔案不要放到jre的ClassPath中,在jre在ClassPath中找到的類隻會加載一次。

2.使用反射擷取類的時,如果需要擷取最新生成的,需要重新執行個體化一個類加載器,因為舊的類加載器已經加載過這個類,再次加載隻會加載上次那個。而重新執行個體化的類加載器沒有加載過這個類,是以會重新去定義、連結和加載。

Java動态編譯和類的重新加載

Main.java

public class Main {
public static void main(String[] args) {
String fullClassName = "MyObj";


String code = "public class MyObj implements MyInterface{public void sayHello(){System.out.println(666);}}";
String code_2 = "public class MyObj implements MyInterface{public void sayHello(){System.out.println(777);}}";
String code_3 = "public class MyObj implements MyInterface{public void sayHello(){System.out.println(888);}}";
load(code,fullClassName);
load(code_2,fullClassName);
load(code_3,fullClassName);
}


private static void load(String code, String fullClassName) {
new MyClassCompiler(fullClassName, code).compile();


try {
MyInterface myObj = (MyInterface) new MyClassLoader().loadClass(
fullClassName).newInstance();
myObj.sayHello();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
           

MyClassCompiler.java

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;


public class MyClassCompiler {
private String simpleClassName;
private String code;
private String classPath = System.getProperty("user.dir") + File.separator + "myFolder";


public MyClassCompiler(String simpleClassName, String code) {
this.simpleClassName = simpleClassName;
this.code = code;
}


public boolean compile() {
try {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaFileObject javaFile = new SimpleJavaFileObject(new URI(
simpleClassName + ".java"), Kind.SOURCE) {
@Override
public CharSequence getCharContent(boolean arg)
throws IOException {
return code;
}
};
CompilationTask task = compiler.getTask(null, null, null,
Arrays.asList("-d", classPath), null,
Arrays.asList(javaFile));
return task.call();
} catch (URISyntaxException e) {
e.printStackTrace();
return false;
}
}


public String getSimpleClassName() {
return simpleClassName;
}


public void setSimpleClassName(String simpleClassName) {
this.simpleClassName = simpleClassName;
}


public String getCode() {
return code;
}


public void setCode(String code) {
this.code = code;
}


public String getClassPath() {
return classPath;
}


public void setClassPath(String classPath) {
this.classPath = classPath;
}
}
           

MyClassLoader.java

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;


public class MyClassLoader extends ClassLoader {

private boolean alwaysDefineClass = true;
private String classPath = System.getProperty("user.dir") + File.separator + "myFolder";


@Override
protected Class<?> findClass(String fullClassName)
throws ClassNotFoundException {
Class<?> clazz = null;
// clazz = findLoadedClass(fullClassName);
// if(alwaysDefineClass || clazz == null){
byte[] raw = readClassBytes(fullClassName);
clazz = defineClass(fullClassName, raw, 0, raw.length);
resolveClass(clazz);
// }


return clazz;
}


private byte[] readClassBytes(String fullClassName) {
byte[] raw = null;
InputStream stream = null;
File file = new File(classPath + File.separator
+ fullClassName.replaceAll("\\.", "/") + ".class");


try {
stream = new FileInputStream(file);
raw = new byte[(int) file.length()];
stream.read(raw);
} catch (Exception e) {


} finally {
try {
stream.close();
} catch (IOException e) {
}
}
return raw;
}


public boolean isAlwaysDefineClass() {
return alwaysDefineClass;
}


public void setAlwaysDefineClass(boolean alwaysDefineClass) {
this.alwaysDefineClass = alwaysDefineClass;
}


public String getClassPath() {
return classPath;
}


public void setClassPath(String classPath) {
this.classPath = classPath;
}
}
           

interface.java

public interface MyInterface {


 public void sayHello();
}