Java类加载机制及自定义加载器
转载:https://www.cnblogs.com/gdpuzxs/p/7044963.html
Java类加载机制及自定义加载器
一:ClassLoader类加载器,主要的作用是将class文件加载到jvm虚拟机中。jvm启动的时候,并不是一次性加载所有的类,而是根据需要动态去加载类,主要分为隐式加载和显示加载。
隐式加载:程序代码中不通过调用ClassLoader来加载需要的类,而是通过JVM类自动加载需要的类到内存中。例如,当我们在类中继承或者引用某个类的时候,JVM在解析当前这个类的时,发现引用的类不在内存中,那么就会自动将这些类加载到内存中。
显示加载:代码中通过Class.forName(),this.getClass.getClassLoader.LoadClass(),自定义类加载器中的findClass()方法等。
Thread. setContextClassLoader() 上下文加载器
是一个角色 用以解决顶层ClassL
类加载器的继承关系
类加载器之间的继承关系,如下图:

ExtClassLoader,AppClassLoder继承URLClassLoader,而URLClassLoader继承ClassLoader,BoopStrap ClassLoder不在上图中,因为它是由C/C++编写的,它本身是虚拟机的一部分,并不是一个java类。jvm加载的顺序:BoopStrap ClassLoder-〉ExtClassLoader->AppClassLoder
oader无法访问底层ClassLoader的类的问题 基本思想是,在顶层ClassLoader中,传入底层ClassLoader的实例
AppClassLoader的父加载器为ExtClassLoader,ExtClassLoader的父加载器为null,BoopStrap ClassLoader为顶级加载器。
一个普通的加载过程:
(1)首先会到自定义加载器中查找,看是否已经加载过,如果已经加载过,则返回字节码。
(2)如果自定义加载器没有加载过,则询问上一层加载器(即AppClassLoader)是否已经加载过Test.class。
(3)如果没有加载过,则询问上一层加载器(ExtClassLoader)是否已经加载过。
(4)如果没有加载过,则继续询问上一层加载(BoopStrap ClassLoader)是否已经加载过。
(5)如果BoopStrap ClassLoader依然没有加载过,则到自己指定类加载路径下("sun.boot.class.path")查看是否有Test.class字节码,有则返回,没有通
知下一层加载器ExtClassLoader到自己指定的类加载路径下(java.ext.dirs)查看。
(6)依次类推,最后到自定义类加载器指定的路径还没有找到Test.class字节码,则抛出异常ClassNotFoundException。如下图:
蓝线:findLoadedClass
红线:loadClass

类加载过程的几个方法
(1)loadClass (2)findLoadedClass (3)findClass
当父类加载器没有加载,并且没有相关的类,则当前类的加载器调用自身findClass,去loadClass
自定义类加载器步骤
(1)继承ClassLoader (2)重写findClass()方法 (3)调用defineClass()方法
下面写一个自定义类加载器:指定类加载路径在D盘下的lib文件夹下。
(1)新建一个Test.class类,代码如下:
package test; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream; public class MyClassLoader extends ClassLoader{ private String classpath; public MyClassLoader(String classpath) { this.classpath = classpath;
} @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte [] classDate=getDate(name); if(classDate==null){} else{
//defineClass方法将字节码转化为类
return defineClass(name,classDate,,classDate.length);
} } catch (IOException e) { e.printStackTrace();
} return super.findClass(name);
}
//返回类的字节码
private byte[] getDate(String className) throws IOException{
InputStream in = null;
ByteArrayOutputStream out = null;
String path=classpath + File.separatorChar +
className.replace('.',File.separatorChar)+".class";
try {
in=new FileInputStream(path);
out=new ByteArrayOutputStream();
byte[] buffer=new byte[];
int len=;
while((len=in.read(buffer))!=-){
out.write(buffer,,len);
}
return out.toByteArray();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
finally{
in.close();
out.close();
}
return null;
}
}
package test; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public class TestMyClassLoader { public static void main(String []args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
//自定义类加载器的加载路径
MyClassLoader myClassLoader=new MyClassLoader("D:\\lib");
//包名+类名
Class c=myClassLoader.loadClass("com.test.Test"); if(c!=null){
Object obj=c.newInstance();
Method method=c.getMethod("say", null);
method.invoke(obj, null);
System.out.println(c.getClassLoader().toString());
}
}
}
自定义类加载器的作用:jvm自带的三个加载器只能加载指定路径下的类字节码。如果某个情况下,我们需要加载应用程序之外的类文件呢?比如本地D盘下的,或者去加载网络上的某个类文件,这种情况就可以使用自定义加载器了。
JDK中ClassLoader默认设计模式 – 问题:

Thread. setContextClassLoader() 上下文加载器 是一个角色 ,用以解决顶层ClassLoader无法访问底层ClassLoader的类的问题
基本思想是,在顶层ClassLoader中,传入底层ClassLoader的实例
双亲模式的破坏:
双亲模式是默认的模式,但不是必须这么做
Tomcat的WebappClassLoader 就会先加载自己的Class,找不到再委托parent
OSGi的ClassLoader形成网状结构,根据需要自由加载Class
热替换:
当一个class被替换后,系统无需重启,替换的类立即生效
面试:描述一下JVM加载class文件的原理机制?
Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。
经过编译的Java程序并不是一个可执行程序,而是.class文件。当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的.class文件中的数据读入到内存中,产生对应的Class对象。加载完成后,以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。
类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。类加载过程采取了父亲委托机制(PDM)。Bootstrap是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。
Bootstrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);
Extension:从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是Bootstrap;
System:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中记载类,是用户自定义加载器的默认父加载器。
Java类加载机制及自定义加载器的更多相关文章
- Java 理解类加载过程 -- 自定义加载器
类加载器可以看下我的收藏: https://www.cnblogs.com/dongguacai/p/5879931.html 现在准备一个字节码文件: 自定义加载器: package com.xzl ...
- JVM类加载(4)—加载器
定义: 虚拟机设计团队把类加载阶段中“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称之为“类加载器 ...
- xLua自定义加载器
xLua入门基础 环境配置 github下载xLua文件: xLua是腾讯开发,据说比较先进: 下载下来后将Plugins和XLua文件夹考进项目: Plugins多平台权限:XLua和C#交互: t ...
- java中三个类别加载器的关系以及各自加载的类的范围
Java在需要使用类别的时候,才会将类别加载,Java的类别载入是由类别载入器(Class loader)来达到的,预设上,在程序启动之后,主要会有三个类别加载器:Bootstrap Loader.E ...
- java反射机制与动态加载类
什么是java反射机制? 1.当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射. IT行业里这么说,没有 ...
- Java基础-类加载机制与自定义类Java类加载器(ClassLoader)
Java基础-类加载机制与自定义类Java类加载器(ClassLoader) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于类加载器的概念和分类我就不再废话了,因为我在之前的笔 ...
- 深入java虚拟机学习 -- 类的加载机制(三)
类的初始化时机 在上篇文章中讲到了类的六种主动使用方式,反射是其中的一种(Class.forName("com.jack.test")),这里需要注意一点:当调用ClasLoade ...
- Java类加载机制深度分析
转自:http://my.oschina.net/xianggao/blog/70826 参考:http://www.ibm.com/developerworks/cn/java/j-lo-class ...
- Day18 (一)类的加载器
一个运行时的Java虚拟机(JVM)负责运行一个Java程序. 当启动一个Java程序时,一个虚拟机实例诞生:当程序关闭退出,这个虚拟机实例也就随之消亡. 如果在同一台计算机上同时运行多个Java程序 ...
随机推荐
- Bar-Code-Recognition-System Private
本设计研究EAN13条形码识别的译码技术,在基于机器视觉技术上,构建了一套条形码在线检测识别系统,系统将由以下几个部分构成:条形码图像定位与采集.计算机图像预处理.条形码图像中值滤波去噪.条码解析与识 ...
- Codeforces Beta Round #27 (Codeforces format, Div. 2)
Codeforces Beta Round #27 (Codeforces format, Div. 2) http://codeforces.com/contest/27 A #include< ...
- 唯品会海量实时OLAP分析技术升级之路
本文转载自公众号 DBAplus社群 , 作者:谢麟炯 谢麟炯,唯品会大数据平台高级技术架构经理,主要负责大数据自助多维分析平台,离线数据开发平台及分析引擎团队的开发和管理工作,加入唯品会以来还曾负责 ...
- mybatis插入数据并获取主键值
有时候我们的主键是自增的,但是我们想要在插入一条数据以后获取这条数据的主键值,而我们知道,mybatis执行完插入操作以后返回的是生效的记录数.那如何才能获取这个主键值呢. 1.在配置文件mapper ...
- Spring <context:annotation-config> 和 <context:component-scan> 区别
一篇很不错的文章,看到就是赚到Get.... https://www.cnblogs.com/leiOOlei/p/3713989.html 说白了 :<context:component-sc ...
- 设置导航栏和TabBar标题的文字格式
//TabBar样式 [navi.tabBarItem setTitleTextAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSiz ...
- RHEL7、CentOS7防火墙管理
经常start.stop.restart操作防火墙有两种方式: 1.service iptables stop 2./etc/init.d/iptables stop 但是经常会有这种错误,因为在RH ...
- go语言log包的学习(log,Logger)
package main; import ( "log" "os" "time" "fmt" ) func main() ...
- sqlserver数据库的备份与还原——完整备份与还原
sqlserver提供四种数据库备份方式 完整备份:备份整个数据库的所有内容包括书屋和日志 差异备份:只备份上次完整备份后更高的数据部分 事务日志备份:只备份事务日志里的内容 文件或文件组备份:只备份 ...
- Ubuntu 16.04 更换阿里源
vim /etc/apt/source.list deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by s ...