java類加載器的知識點總結以及簡單實現

一、類加載器的種類

一般分爲:引導類加載器(bootstrap classloader)、擴展類加載器(extensions class loader)、應用程序類加載器(application class loader)、自定義類加載器 這4種類加載器

 

一、引導類加載器(bootstrap classloader)

 它用來加載java核心庫的(java_home/jre/lib/rt.jar 或者sun.boot.class.path 路徑下的內容)是用來原生代碼來實現的,並不繼承java.lang.classloader,是通過C++來實現。由於引導類加載器涉及到虛擬機本地實現細節,開發者無法直接獲取到啓動類加載器的引用,所以不允許直接通過引用進行操作。

二、擴展類加載器(extensions class loader)

 用來加載java的擴展(java_home/jre/ext/*.jar 或者java.ext.dirs路徑下的內容)

 java與虛擬機的實現會提供一個擴展庫的目錄,該類加載器在此目錄裏面查找並加載java類

由sun.misc.Launcher$ExtClassLoader實現

三、應用程序類加載器(application class loader)

它根據java引用的類路徑(classpath java.class.path路徑

一般來說java應用的類的都是由他來來加載實現的,也就是我們經常用到的classpath路徑

package classLoader;

public class ClassLoader_test {
	public static void main(String[] args) {
		System.out.println(ClassLoader.getSystemClassLoader());
	}

}
sun.misc.Launcher$AppClassLoader@4e25154f

通過getparent()來獲取相對應的父級

package classLoader;

public class ClassLoader_test {
	public static void main(String[] args) {
		System.out.println(ClassLoader.getSystemClassLoader());
		//AppClassLoader的父類應該是ExtClassLoader
		System.out.println(ClassLoader.getSystemClassLoader().getParent());
		//而ExtClassLoader的父類應該是bootstrap classloader,但是它是由C++實現的,那麼java中是獲取不到的
		System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
	}

}
sun.misc.Launcher$AppClassLoader@4e25154f
sun.misc.Launcher$ExtClassLoader@33909752
null

四、加載機制

代理模式

  交給其他加載器來加載指定的類

雙親委託機制

 就是給某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父類加載器,依次追溯,直到最高的爺爺輩的,如果父類加載器可以完成類加載額任務,就成功返回;只有父類加載器無法完成的此加載任務時,自己纔去加載

雙親委託機制是爲了保證java核心庫的類型安全

 這種機制就保證不會出現用戶自己能定義java.lang.Object類的情況

類加載器處理用於加載類,也是安全的最基本的保障

雙親委託機制是代理模式的一種

 並不是所有的類加載器都採用雙親委託機制

 tomcat服務器的類加載器也是採用代理模式,所不同的它首先嚐試去加載某個類,如果找不到再代理給父類加載器,這與一般類加載器的順序是相反的。

 

舉個栗子

 

比如我突然naocan,定義了一個java.lang.String的類,那麼首先是從自定義類加載器開始,先傳遞給AppClassLoader,然後在傳遞給ExtClassLoader,最後傳遞給BootStrapclassLoader(加載核心包的),發現存在java.lang.String,那麼就會加載String類,那麼就會直接返回class。這樣就保證了對於外部的包進行了安全性的保障

五、 java.lang.classLoader

作用:

 java.lang.classLoader的類的基本職責就是根據一個指定的類的名稱,找到或者生成其對應的字節代碼,然後從這些字節代碼中定義java類,即java.lang.Class類的一個實例

 除此之外,ClassLoader還負責加載java應用所需的資源,如圖像文件和配置文件

相關方法:

 getParent()  返回該類加載器的父類加載器

loadClass(String name) 加載名稱爲name的類,返回的結果是java.lang.class類的實例

Findclass(String name) 查找名稱爲name的類,返回的結果是java.lang.class的類的實例

defineClass(String name,byte[] b,int off,int lent) 把字節數組b中的 內容轉化爲java類,返回的是

Java.lang.class的類的實例,這個方法被聲明爲final的

resolveClass(Class<?> c)鏈接被指定的java類

對於以上給出的方法,表示類的名稱的name參數的值是類的二進制名稱,需要注意的是內部類的表示,如com.example.Sample$1和com.example.Sample$inner等表示方式

六、自定義加載器

package classLoader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import javassist.ByteArrayClassPath;

public class FileSystemClassLoader extends ClassLoader {
	private String rootDir;
	//定義了文件所在的根目錄
	public  FileSystemClassLoader(String root)
	{
		this.rootDir=root;
	}
	@Override
    protected Class<?> findClass(String  name)throws ClassNotFoundException
    {
    	Class<?> class1=findLoadedClass(name);
    	//如果已經被加載了
    	if(class1!=null)
    	{
    		return class1;
    		
    	}
    	else 
    	{
    		
    	ClassLoader parent=this.getParent();
    	//讓父級進行加載,如果加載成功那麼直接返回
    	try
    	{
    	class1=parent.loadClass(name);
    	}
    	catch(Exception exception)
    	{
    		exception.printStackTrace();        
    	}
    	if(class1!=null)
    		return class1;
    	else 
    	{
    		byte[] classData = null;
			try {
				classData = getClassData(name);
			} catch (IOException e) {
				// TODO 自動生成的 catch 塊
				e.printStackTrace();
			}
    		if(classData==null)
    			 throw new ClassNotFoundException();
    		else 
    		{System.out.println(name+""+classData.toString()+"     "+classData.length);
    			class1=defineClass(name, classData, 0,classData.length);	
    		}
    	}
    	}
    	
    	return class1;
    	
    }
    public byte[] getClassData(String classname) throws IOException
    { String path=rootDir+"/"+classname.replace('.', '/')+".class";
    System.out.println(path);
    InputStream is=new FileInputStream(path);
    ByteArrayOutputStream byteArrayOutputStream=null;
    byte[] bs=new byte[1024];
    int length=0;
    try
    {
    	byteArrayOutputStream= new ByteArrayOutputStream();
    while((length=is.read(bs))!=-1)
    	byteArrayOutputStream.write(bs,0,length);
    return byteArrayOutputStream.toByteArray();
    }
    catch (Exception e) {
		// TODO: handle exception
    	e.printStackTrace();
    	System.out.println("wo是你個");
    	return null;
    	
	}
    finally {
        byteArrayOutputStream.close();
    	 is.close();
	}
   
   

    	
    }

}
package classLoader;

public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException {
	FileSystemClassLoader FilesystemClassLoader=new FileSystemClassLoader("d:/myjava");
     Class<?> class1=	FilesystemClassLoader.loadClass("com.bjsxt.bean.HelloWorld");
	System.out.println(class1);
}
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章