天天看點

自定義ClassLoader動态加載Class

1、自定義ClassLoader代碼如下:

package zmx.classloader.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashSet;

/*
 *  實作熱部署,自定義ClassLoader,加載的是.class
 */
public class CustomClassLoader extends ClassLoader {

	private String basedir; // 需要該類加載器直接加載的類檔案的基目錄
	private HashSet<String> dynaclazns; // 需要由該類加載器直接加載的類名

	public CustomClassLoader(String basedir, String[] clazns) {
		super(null); // 指定父類加載器為 null
		this.basedir = basedir;
		dynaclazns = new HashSet<>();
		loadClassByMe(clazns);
	}

	private void loadClassByMe(String[] clazns) {
		for (int i = 0; i < clazns.length; i++) {
			loadDirectly(clazns[i]);
			dynaclazns.add(clazns[i]);
		}
	}

	private Class loadDirectly(String name) {
		Class cls = null;
		StringBuffer sb = new StringBuffer(basedir);
		String classname = name.replace('.', File.separatorChar) + ".class";
		sb.append(File.separator + classname);
		File classF = new File(sb.toString());
		try {
			cls = instantiateClass(name, new FileInputStream(classF),classF.length());
		} catch (FileNotFoundException e) {			
			e.printStackTrace();
		}
		return cls;
	}

	private Class instantiateClass(String name, InputStream fin, long len) {
		byte[] raw = new byte[(int) len];
		try {
			fin.read(raw);
			fin.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return defineClass(name, raw, 0, raw.length);
	}

	protected Class loadClass(String name, boolean resolve)
			throws ClassNotFoundException {
		Class cls = null;
		cls = findLoadedClass(name);
		if (!this.dynaclazns.contains(name) && cls == null)
			cls = getSystemClassLoader().loadClass(name);
		if (cls == null)
			throw new ClassNotFoundException(name);
		if (resolve)
			resolveClass(cls);
		return cls;
	}
}

/*
 * 每隔500ms運作一次,不斷加載class
 */
class Multirun implements Runnable {
	public void run() {
		try {
			while (true) {
				// 每次都建立出一個新的類加載器
				// class需要放在自己package名字的檔案夾下
				String url = System.getProperty("user.dir") + "/WebRoot/WEB-INF/classes";  // "D:/projects/testWeb/WebRoot/WEB-INF/classes/zmx/classloader/test/DynamicClass.class";
				CustomClassLoader cl = new CustomClassLoader(url, new String[] { "zmx.classloader.test.DynamicClass" });
				Class cls = cl.loadClass("zmx.classloader.test.DynamicClass");
				Object foo = cls.newInstance();
				// 被調用函數的參數
				Method m = foo.getClass().getMethod("Output", new Class[] {});
				m.invoke(foo, new Object[] {});
				Thread.sleep(500);
			}

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}
           

        使用上述類加載器,加載動态類.

2、DynamicClass.java代碼如下:

package zmx.classloader.test;

public class DynamicClass {

 public static double Darts(int n) 

   { 

     int k = 0; 

     double x = 0.0D;    

     double y = 0.0D;    

     for (int i = 0; i < n; i++) 

     { 

       x = Math.random(); 

       y = Math.random();    

       if (x * x + y * y <= 1.0D) 

         k++; 

     } 

     return 4 * k / n; 

   } 

   // 本熱部署實驗中,上面的Darts函數沒有用到,請忽略 

   public static void Output() {       

     System.out.println("Frist Class Output"); 

   }

}

3、測試類MainTest.java代碼如下:

package zmx.classloader.test;

import java.lang.reflect.Method;

import java.net.URL;

import java.net.URLClassLoader;

public class MainTest {

 public static Method initAddMethod() {

  try {

   Method add = URLClassLoader.class.getDeclaredMethod("addURL",new Class[] { URL.class });

   add.setAccessible(true);

   return add;

  } catch (Exception e) {

   throw new RuntimeException(e);

  }

 }

 public static void main(String[] args) throws Exception{

  // 熱部署測試代碼

  Thread t;

  t = new Thread(new Multirun());

  t.start();

 }

}

    程式運作過程中将DynamicClass中的Output()的輸出修改為 System.out.println("Second Class Output");重新編譯。即 運作時候,程式加載指定檔案夾下的.class,即開始輸出 Frist Class Output ,然後手動将另外一個.class(輸出Second Class Output的.class)覆寫此檔案。程式輸出為 Second Class Output。

輸出結果如下:

Frist Class Output

Frist Class Output

Frist Class Output

Frist Class Output

Frist Class Output

Frist Class Output

Second Class Output

Second Class Output

Second Class Output

Second Class Output