java classloader详解_Java的ClassLoader机制解析

JVM在加载类的时候,都是通过ClassLoader的loadClass()方法来加载class的,loadClass(String name)方法:

使用的是双亲委托模式:

jvm启动时,会启动jre/rt.jar里的类加载器:bootstrap classloader,用来加载java核心api;然后启动扩展类加载器ExtClassLoader加载扩展类,并加载用户程序加载器AppClassLoader,并指定ExtClassLoader为他的父类;

当类被加载时,会先检查在内存中是否已经被加载,如果是,则不再加载,如果没有,再由AppClassLoader来加载,先从jar包里找,没有再从classpath里找;

如果自定义loader类,就会存在这命名空间的情况,不同的加载器加载同一个类时,产生的实例其实是不同的;

Java代码

publicClass> loadClass(String name)throwsClassNotFoundException {

returnloadClass(name,false);

}

publicClass> loadClass(String name)throwsClassNotFoundException {

returnloadClass(name,false);

}

loadClass(String name)方法再调用loadClass(String name, boolean resolve)方法:

◆ name - 类的二进制名称

◆ resolve - 如果该参数为 true,则分析这个类

Java代码

protectedsynchronizedClass> loadClass(String name,booleanresolve)

throwsClassNotFoundException

{

// First, check if the class has already been loaded

//JVM 规范规定ClassLoader可以在缓存保留它所加载的Class,如果一个Class已经被加载过,则直接从缓存中获取

Class c = findLoadedClass(name);

if(c ==null) {

try{

if(parent !=null) {

c = parent.loadClass(name, false);

} else{

c = findBootstrapClass0(name);

}

} catch(ClassNotFoundException e) {

// If still not found, then invoke findClass in order

// to find the class.

c = findClass(name);

}

}

if(resolve) {

resolveClass(c);

}

returnc;

}

protectedsynchronizedClass> loadClass(String name,booleanresolve)

throwsClassNotFoundException

{

// First, check if the class has already been loaded

//JVM 规范规定ClassLoader可以在缓存保留它所加载的Class,如果一个Class已经被加载过,则直接从缓存中获取

Class c = findLoadedClass(name);

if(c ==null) {

try{

if(parent !=null) {

c = parent.loadClass(name, false);

} else{

c = findBootstrapClass0(name);

}

} catch(ClassNotFoundException e) {

// If still not found, then invoke findClass in order

// to find the class.

c = findClass(name);

}

}

if(resolve) {

resolveClass(c);

}

returnc;

}

如果ClassLoader并没有加载这个class,则调用findBootstrapClass0:

Java代码

privateClass findBootstrapClass0(String name)

throwsClassNotFoundException

{

check();

if(!checkName(name))

thrownewClassNotFoundException(name);

returnfindBootstrapClass(name);

}

privateClass findBootstrapClass0(String name)

throwsClassNotFoundException

{

check();

if(!checkName(name))

thrownewClassNotFoundException(name);

returnfindBootstrapClass(name);

}

该方法会调用check()方法来判断这个类是否已经初始化,并且通过checkName(name)来判断由name指定的这个类是否存在***调用findBootstrapClass(name):

Java代码

privatenativeClass findBootstrapClass(String name)

throwsClassNotFoundException;

privatenativeClass findBootstrapClass(String name)

throwsClassNotFoundException;

而这个findBootstrapClass方法是一个native方法,这是我们的root loader,这个载入方法并非是由JAVA所写,而是C++写的,它会最终调用JVM中的原生findBootstrapClass方法来完成类的加载。

如果上面两个都找不到,则使用findClass(name)来查找指定类名的Class:

Java代码

protectedClass> findClass(String name)throwsClassNotFoundException {

thrownewClassNotFoundException(name);

}

protectedClass> findClass(String name)throwsClassNotFoundException {

thrownewClassNotFoundException(name);

}

JDK5.0中的说明:

使用指定的二进制名称查找类。此方法应该被类加载器的实现重写,该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后,此方法将被 loadClass 方法调用。默认实现抛出一个ClassNotFoundException。

所以,我们在自定义类中,只需要重写findClass()即可。

MyClassLoader类:

Java代码

publicclassMyClassLoaderextendsClassLoader {

privateString fileName;

publicMyClassLoader(String fileName) {

this.fileName = fileName;

}

protectedClass> findClass(String className)throwsClassNotFoundException {

Class clazz = this.findLoadedClass(className);

if(null== clazz) {

try{

String classFile = getClassFile(className);

FileInputStream fis = newFileInputStream(classFile);

FileChannel fileC = fis.getChannel();

ByteArrayOutputStream baos = new

ByteArrayOutputStream();

WritableByteChannel outC = Channels.newChannel(baos);

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

while(true) {

inti = fileC.read(buffer);

if(i ==0|| i == -1) {

break;

}

buffer.flip();

outC.write(buffer);

buffer.clear();

}

fis.close();

byte[] bytes = baos.toByteArray();

clazz = defineClass(className, bytes, 0, bytes.length);

} catch(FileNotFoundException e) {

e.printStackTrace();

} catch(IOException e) {

e.printStackTrace();

}

}

returnclazz;

}

privatebyte[] loadClassBytes(String className)throws

ClassNotFoundException {

try{

String classFile = getClassFile(className);

FileInputStream fis = newFileInputStream(classFile);

FileChannel fileC = fis.getChannel();

ByteArrayOutputStream baos = new

ByteArrayOutputStream();

WritableByteChannel outC = Channels.newChannel(baos);

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

while(true) {

inti = fileC.read(buffer);

if(i ==0|| i == -1) {

break;

}

buffer.flip();

outC.write(buffer);

buffer.clear();

}

fis.close();

returnbaos.toByteArray();

} catch(IOException fnfe) {

thrownewClassNotFoundException(className);

}

}

privateString getClassFile(String name) {

StringBuffer sb = newStringBuffer(fileName);

name = name.replace('.', File.separatorChar) +".class";

sb.append(File.separator + name);

returnsb.toString();

}

}

publicclassMyClassLoaderextendsClassLoader {

privateString fileName;

publicMyClassLoader(String fileName) {

this.fileName = fileName;

}

protectedClass> findClass(String className)throwsClassNotFoundException {

Class clazz = this.findLoadedClass(className);

if(null== clazz) {

try{

String classFile = getClassFile(className);

FileInputStream fis = newFileInputStream(classFile);

FileChannel fileC = fis.getChannel();

ByteArrayOutputStream baos = new

ByteArrayOutputStream();

WritableByteChannel outC = Channels.newChannel(baos);

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

while(true) {

inti = fileC.read(buffer);

if(i ==0|| i == -1) {

break;

}

buffer.flip();

outC.write(buffer);

buffer.clear();

}

fis.close();

byte[] bytes = baos.toByteArray();

clazz = defineClass(className, bytes, 0, bytes.length);

} catch(FileNotFoundException e) {

e.printStackTrace();

} catch(IOException e) {

e.printStackTrace();

}

}

returnclazz;

}

privatebyte[] loadClassBytes(String className)throws

ClassNotFoundException {

try{

String classFile = getClassFile(className);

FileInputStream fis = newFileInputStream(classFile);

FileChannel fileC = fis.getChannel();

ByteArrayOutputStream baos = new

ByteArrayOutputStream();

WritableByteChannel outC = Channels.newChannel(baos);

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

while(true) {

inti = fileC.read(buffer);

if(i ==0|| i == -1) {

break;

}

buffer.flip();

outC.write(buffer);

buffer.clear();

}

fis.close();

returnbaos.toByteArray();

} catch(IOException fnfe) {

thrownewClassNotFoundException(className);

}

}

privateString getClassFile(String name) {

StringBuffer sb = newStringBuffer(fileName);

name = name.replace('.', File.separatorChar) +".class";

sb.append(File.separator + name);

returnsb.toString();

}

}

该类中通过调用defineClass(String name, byte[] b, int off, int len)方法来定义一个类:

Java代码

protectedfinalClass> defineClass(String name,byte[] b,intoff,intlen)

throwsClassFormatError

{

returndefineClass(name, b, off, len,null);

}

protectedfinalClass> defineClass(String name,byte[] b,intoff,intlen)

throwsClassFormatError

{

returndefineClass(name, b, off, len,null);

}

注:MyClassLoader加载类时有一个局限,必需指定.class文件,而不能指定.jar文件。该类中的大部分代码是从网上搜索到的,是出自一牛人之笔,只是不知道原帖在哪,希望不会被隐藏。

MainClassLoader类:

Java代码

publicclassMainClassLoader {

publicstaticvoidmain(String[] args) {

try{

MyClassLoader tc = newMyClassLoader("F:\\OpenLib\\");

Class c = tc.findClass("Test");

c.newInstance();

} catch(ClassNotFoundException e) {

e.printStackTrace();

} catch(IllegalAccessException e) {

e.printStackTrace();

} catch(InstantiationException e) {

e.printStackTrace();

}

}

}

publicclassMainClassLoader {

publicstaticvoidmain(String[] args) {

try{

MyClassLoader tc = newMyClassLoader("F:\\OpenLib\\");

Class c = tc.findClass("Test");

c.newInstance();

} catch(ClassNotFoundException e) {

e.printStackTrace();

} catch(IllegalAccessException e) {

e.printStackTrace();

} catch(InstantiationException e) {

e.printStackTrace();

}

}

}

***是一个简单的Test测试类:

Java代码

publicclassTest

{

publicTest() {

System.out.println("Test");

}

publicstaticvoidmain(String[] args) {

System.out.println("Hello World");

}

}

原文链接:http://huangcanqin.iteye.com/blog/1273170

【编辑推荐】

【责任编辑:小林 TEL:(010)68476606】

点赞 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值