java自定义类加载器代码示例
如果要使用自定义类加载器加载class文件,就需要继承java.lang.ClassLoader类。
ClassLoader有几个重要的方法:
protectedClassLoader(ClassLoaderparent):使用指定的、用于委托操作的父类加载器创建新的类加载器。
protectedfinalClass>defineClass(Stringname,byte[]b,intoff,intlen):将一个byte数组转换为Class类的实例。
protectedClass>findClass(Stringname):使用指定的二进制名称查找类。
publicClass>loadClass(Stringname):使用指定的二进制名称来加载类。
protectedfinalClass>findLoadedClass(Stringname):如果Java虚拟机已将此加载器记录为具有给定二进制名称的某个类的启动加载器,则返回该二进制名称的类。否则,返回null。
publicfinalClassLoadergetParent():返回委托的父类加载器。
protectedfinalvoidresolveClass(Class>c):链接指定的类。
如果要遵循双亲委派模型,则重写findClass(Stringname)方法;如果不想遵循双亲委派模型,则直接重写loadClass(Stringname)方法。
自定义遵循双亲委派模型的类加载器
ParentsDelegateClassLoader.java
packagecom.zzj.classloader;
importjava.io.ByteArrayOutputStream;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.InputStream;
/**
*双亲委派类加载器,重写findClass(name)方法
*
*@authorAdministrator
*
*/
publicclassParentsDelegateClassLoaderextendsClassLoader{
privatestaticfinalStringEXT=".class";
privateStringpath;
publicParentsDelegateClassLoader(){
path=this.getResource("").getPath();
}
publicParentsDelegateClassLoader(Stringpath){
this.path=path;
}
@Override
protectedClass>findClass(Stringname)throwsClassNotFoundException{
byte[]b=null;
try{
b=loadClassFile(name);
}
catch(IOExceptione){
e.printStackTrace();
}
returnthis.defineClass(name,b,0,b.length);
}
privatebyte[]loadClassFile(Stringname)throwsIOException{
StringclassFile=getClassFile(name);
System.out.println("即将加载class文件"+classFile);
ByteArrayOutputStreamout=newByteArrayOutputStream();
InputStreaminput=newFileInputStream(classFile);
intcount;
byte[]temp=newbyte[1024];
while((count=input.read(temp))>-1){
out.write(temp,0,count);
}
out.close();
input.close();
returnout.toByteArray();
}
privateStringgetClassFile(Stringname){
StringpathName=name.replace(".",File.separator);
if(path.endsWith("/")||path.endsWith("\\")){
returnpath+pathName+EXT;
}
returnpath+File.separator+pathName+EXT;
}
}
现在类路径classpath下和F:\\ClassloaderTest\\bin目录下都有一个类文件com\zzj\classloader\User.class,包名为com.zzj.classloader,使用类加载器ParentsDelegateClassLoader加载F:\\ClassloaderTest\\bin下的类。
packagecom.zzj.classloader;
publicclassApp{
privatestaticfinalStringpath="F:\\ClassloaderTest\\bin";
privatestaticfinalStringclassname="com.zzj.classloader.User";
publicstaticvoidmain(String[]args)throwsException{
ParentsDelegateClassLoaderclassLoader=newParentsDelegateClassLoader(path);
Class>clazz=classLoader.loadClass(classname);
System.out.println(clazz);
System.out.println(clazz.getClassLoader());
}
}
输出:
classcom.zzj.classloader.User sun.misc.Launcher$AppClassLoader@19821f
User类的加载器是系统类加载器AppClassLoader,而不是我们自己定义的类加载。实际上被加载不是F:\\ClassloaderTest\\bin下的类,而是classpath下的类。这就是双亲委派模型:当ParentsDelegateClassLoader加载器接收到加载请求后,会先委托给父类加载器,如果父类加载器加载成功,则返回一个Class对象。如果加载失败,才会让接收到加载请求的类加载器加载。
把classpath下的User类删掉测试运行:
即将加载class文件F:\ClassloaderTest\bin\com\zzj\classloader\User.class classcom.zzj.classloader.User com.zzj.classloader.ParentsDelegateClassLoader@61de33
此时User类的加载为ParentsDelegateClassLoader。
这一点可以从ClassLoader的源码中得到验证:
publicClass>loadClass(Stringname)throwsClassNotFoundException{
returnloadClass(name,false);
}
调用了重载方法:
protectedsynchronizedClass>loadClass(Stringname,booleanresolve)
throwsClassNotFoundException
{
//先判断该类是否已被当前的类加载器加载
Classc=findLoadedClass(name);
if(c==null){
try{
if(parent!=null){//如果存在父类加载器,则委派给父类加载
c=parent.loadClass(name,false);
}else{//如果父类加载为空,则其父类加载器为引导类加载器
c=findBootstrapClass0(name);
}
}catch(ClassNotFoundExceptione){
//如果父类加载器加载失败,则自己加载,调用的就是findClass方法!
c=findClass(name);
}
}
if(resolve){
resolveClass(c);
}
returnc;
}
可见,如果想要破坏双亲委派模型,可以直接重写loadClass(Stringname)方法。
自定义不遵循双亲委派模型的类加载器
NotParentsDelegateClassLoader.java
packagecom.zzj.classloader;
importjava.io.ByteArrayOutputStream;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.IOException;
importjava.io.InputStream;
/**
*非双亲委派类加载器,重写loadClass(name)方法
*
*@authorAdministrator
*
*/
publicclassNotParentsDelegateClassLoaderextendsClassLoader{
privatestaticfinalStringEXT=".class";
privateStringpath;
publicNotParentsDelegateClassLoader(){
path=this.getResource("").getPath();
}
publicNotParentsDelegateClassLoader(Stringpath){
this.path=path;
}
@Override
publicClass>loadClass(Stringname)throwsClassNotFoundException{
byte[]b=null;
try{
b=loadClassFile(name);
}
catch(FileNotFoundExceptione){
System.err.println("加载器"+this.getClass().getName()
+"没有找到class文件"+name+",将委派给父类加载器!");
//委派给父类加载器
returngetClass().getClassLoader().loadClass(name);
}
catch(IOExceptione){
System.err.println("加载器"+this.getClass().getName()+"加载class文件"
+name+"失败,将委派给父类加载器!");
//委派给父类加载器
returngetClass().getClassLoader().loadClass(name);
}
//检查该类是否被当前类加载器加载过(只检查当前类加载器,不会检查父类加载器)
Class>clazz=findLoadedClass(name);
if(clazz!=null){
System.out.println("类"+name+"已被加载过!");
returnclazz;
}else{
System.out.println("类"+name+"尚未被加载!");
}
returnthis.defineClass(name,b,0,b.length);
}
privatebyte[]loadClassFile(Stringname)throwsIOException,
FileNotFoundException{
StringclassFile=getClassFile(name);
System.out.println("即将加载class文件"+classFile);
ByteArrayOutputStreamout=newByteArrayOutputStream();
InputStreaminput=newFileInputStream(classFile);
intcount;
byte[]temp=newbyte[1024];
while((count=input.read(temp))>-1){
out.write(temp,0,count);
}
out.close();
input.close();
returnout.toByteArray();
}
privateStringgetClassFile(Stringname){
StringpathName=name.replace(".",File.separator);
if(path.endsWith("/")||path.endsWith("\\")){
returnpath+pathName+EXT;
}
returnpath+File.separator+pathName+EXT;
}
}
现在类路径classpath下有一个类文件com\zzj\classloader\User.class,包名为com.zzj.classloader,使用类加载器NotParentsDelegateClassLoader加载User类。
packagecom.zzj.classloader;
publicclassApp2{
privatestaticfinalStringclassName="com.zzj.classloader.User";
publicstaticvoidmain(String[]args)throwsException{
NotParentsDelegateClassLoaderclassLoader=newNotParentsDelegateClassLoader();
Class>clazz=classLoader.loadClass(className);
System.out.println(clazz);
System.out.println(clazz.getClassLoader());
}
}
输出:
即将加载class文件/E:/Myeclipse/zzjtest/WebRoot/WEB-INF/classes/com\zzj\classloader\User.class 类com.zzj.classloader.User尚未被加载! 即将加载class文件/E:/Myeclipse/zzjtest/WebRoot/WEB-INF/classes/java\lang\Object.class classcom.zzj.classloader.User com.zzj.classloader.NotParentsDelegateClassLoader@61de33 加载器com.zzj.classloader.NotParentsDelegateClassLoader没有找到class文件java.lang.Object,将委派给父类加载器!
此时User类的加载器是NotParentsDelegateClassLoader,没有先委托给父类,只有加载失败才会委托给父类加载器,正好跟双亲委派模型是反的。
当然,即使加载失败,也可以不委托给父类加载器,而指定其他的类加载器,从而可以构建更加复杂的网状模型的类加载机制
总结
以上就是本文关于java自定义类加载器代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。