类的加载及双亲委托机制


一.类的加载
1:概述
1:当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载-连接-初始化主要三步来实现这个类进行初始化.
2:得到类加载器: Class#getClassLoader()
3:类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。
任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性
1.加载
1.1.1就是指将class文件读入内存(JVM方法区),并为之创建一个class对象(成员变量,成员方法,构造方法).
1.1.2任何类被使用系统都会建立一个class对象.
2:连接
1.2.1:验证 是否有正确的内部结构,并和其他类协调一致
1.2.2:准备 负责为类的静态成员分配内存(静态是随着类的加载而加载),并设置默认初始化值
1.2.3:解析 将类的二进制数据中的符号引用替换为直接引用 .
3:初始化
2:类加载(初始化)时机
1.2.1:创建类的实例
1.2.2:访问类的静态变量或者为静态变量赋值
1.2.3:调用类的静态方法
1.2.4:使用反射方法来强制创建某个类或接口对应的java.lang.Class对象
1.2.5:初始化某个类的子类
1.2.6:直接使用java.exe命令来运行某个主类
3:类加载器的组成分类
1:类的加载机制:就是将class文件加载到内存中,并为之生成对应的class对象,
2:根类加载器>扩展类加载器>系统类加载器
1:根类加载器(引导类加载器) (Bootstrap classLoader)
1.负责Java核心类的加载,,作为虚拟机的一部分,比如system.string,在JDK的jre的lib目录下的rt.jar文件中



2:扩展类加载器(Extension classLoader)
2.负责jre的扩展目录下的jar包的加载,在JDK中jre的lib目录下的ext目录

3:系统类加载器 (system classLoader)
1.负责在jvm启动时加载来自Java命令的class文件,以及classpath环境变量所指定的jar包和类的路径,包含了所有jdk提供的类(rt-jar).包含开发人员写的类和第三方的jar包
2:加载classpath下的类
3:也叫Application ClassLoader ,sun.misc.Launcher$AppClassLoader, 它是System.getClassLoader()的返回值



4:类加载器的委托机制
1:类加载器的关系
1:系统类加载器的上层领导----------->扩展类加载器
2:扩展类加载器的上层领导----------->根类加载器
2:委托机制执行顺序
1:创建了一个对象 User user=new User();
2:系统类加载器发现了new User这个类
1:系统会给自动的领导打电话,让扩展去自己的地盘去加载user类
2:扩展会给自己的领导打电话,让根类加载器去自己的地盘去加载user类
1:根类加载器去jre下的rt.jar去寻找A类
->1:如果找到了,就进行加载,然后返回user对象的class对象给扩展类加载器,扩展类加载器将这个user.class文件返回给系统类加载器
->2:如果没找到
1:根类加载器返回给扩展一个null,扩展会在自己的地盘上寻找user类
->1:如果扩展类找到了user类,就进行加载,返回user对象的class文件给系统类加载器
-> 2:如果没找到
1:扩展类返回给系统类加载器一个null,系统去自己的地盘(应用程序) 加载A类
->1:如果找到了,加载,返回这个class文件,结束
->2:如果没找到,抛出classNotFoundException类为未找到异常


3:双亲委派模型
1:概述
双亲委派模型的过程:如果一个类加载器收到了类加载的请求,首先不会自己去加载,而是把请求为派给自己的父类加载器去完成,每一个层次的类加载器都是如此。因此所有的加载请求最终都应该传送到顶层的启动类加载器中。只有当父类反馈自己无法完成这个加载请求时,子类加载器才会尝试自己完成

2:破坏双亲委派模型
1:三次大规模破坏该模型的情况
1:JDK 1.0->1.2 , loadClass() -> findClass()
2:模型缺陷:JNDI服务,SPI扩展类是由厂商自己实现,而启动类加载又不可能认识这些类。只好引入 线程上下文 类加载器Thread Context ClassLoader. 该类加载器可以通过setContextClassLoader()设置,如果创建线程时未设置,将会从父线程继承。如果在应用的全局范围内都没有设置,那就默认是AppClassLoader.  有了这个,JNDI服务就可以去加载所需的SPI扩展代码,也就是父类加载器请求子类加载器去完成类加载的动作。这其实也就违背了双亲委派模型的一般性原则,但无可奈何。
3:程序动态性的追求: “热替换” , OSGI. JSR-291

2:开发自己的类加载器

4:类加载安全机制
1:类的加载会从根类加载器---扩展类加载器---系统类加载器一层一层的往下找,不会出现重复加载的情况
2:自己写一个类Java.lang.string,想去替换Java根类库
1:是不会加载的,因为根类加载器中有Java.lang.string.是不会加载自己写的类的
5:类加载器与线程
1:每一个线程都有一个单独的类加载器和cpu寄存器(记录线程的工作状态)
2:getContextClassLoader:获取当前线程的类加载器

二:自定义类加载器
1:应用背景
主 流的Java Web服务器,比如Tomcat,都实现了自定义的类加载器(一般都不止一个)。因为一个功能健全的Web服务器,要解决如下几个问题:
1:部署在同一个服务器上的两个Web应用程序所使用的Java类库可以实现相互隔离。这是最基本的要求,两个不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求一个类库在一个服务器中只有一份,服务器应当保证两个应用程序的类库可以互相使用
2:部署在同一个服务器上的两个Web应用程序所使用的Java类库可以相互共享。这个需求也很常见,比如相同的Spring类库10个应用程序在用不可能分别存放在各个应用程序的隔离目录中
3:支持热替换,我们知道JSP文件最终要编译成.class文件才能由虚拟机执行,但JSP文件由于其纯文本存储特性,运行时修改的概率远远大于第三方类库或自身.class文件,而且JSP这种网页应用也把修改后无须重启作为一个很大的优势看待
4:由于存在上述问题,因此Java提供给用户使用的ClassLoader就无法满足需求了。Tomcat服务器就有自己的ClassLoader架构,当然,还是以双亲委派模型为基础的:
2:简述
1:自定义classLoader加载类是通过loadClass()方法类完成
2:自定义类加载器必须继承ClassLoader这个静态类
3:在JVM的方法区中查询已被加载过的类,判断当前类是否被加载过
3:Java.lang.classLoader源代码
1:加载类通过loadClass方法
2: synchronized (getClassLoadingLock(name) 线程同步,线程锁


4:自定义类加载器的Demo


1:将class文件以.分割的替换为\\磁盘资源转移符,并加上后缀.class
2:将class文件也流的方式读入内存中
classpath,类加载器管理的片区+.class文件名字

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java类加载器采用双亲委派机制,这是Java安全模型的重要组成部分。这种机制保证Java核心API不会被随意篡改,同时也保证了Java程序的稳定性和安全性。 双亲委派机制的基本原则是:当一个类加载器接收到类加载请求时,它首先将该请求委派给它的父类加载器去完成,直到最顶层的父类加载器。只有在父类加载器无法完成类加载任务时,才由子类加载器自行加载。这种机制确保了Java核心API的安全性,因为只有Bootstrap ClassLoader能够加载Java核心API,其他类加载器都无法篡改这些。 在双亲委派机制中,每个类加载器都有一个父类加载器。如果一个类加载器需要加载某个,它会先委托给它的父类加载器去加载。如果父类加载器无法加载,才会由该类加载器自己去加载。这样一来,如果一个已经被加载了,那么其类加载器的父类加载器肯定已经加载了该,因此不会重复加载,也就避免了的重复加载双亲委派机制的实现是通过ClassLoader的loadClass()方法实现的。这个方法首先检查是否已经加载了该,如果已经加载了就直接返回,否则就委托给父类加载器去加载。如果父类加载器无法加载,就调用findClass()方法自己加载。这样一来,每个类加载器都只需要实现自己的findClass()方法,而loadClass()方法则由ClassLoader统一实现,从而实现了双亲委派机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值