JVM类加载机制

概述

class物理文件加载到JVM内存中,可以有多种加载方式:

  • 3种JDK自带的ClassLoader.
  • 自定义的ClassLoader(重写ClassLoader)
  • 反射、JDK动态代理、CGLIB也可以实现运行期编译生成一个新的java对象

类的加载器和核心类

  1. 核心类加载器
  • BootstrapClassLoader 最顶层的加载类,负责加载lib下的rt.jar、resources.jar、charsets.jar和class等
  • ExtentionClassLoader 加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件
  • AppClassLoader 加载当前应用的classpath的所有类
  • 自定义ClassLoader,可以突破class文件包路径的限制,可以修改类加载机制(比如热加载),需要重写findClass()缓存查找方法制定寻找路径即可
  1. 加载的特点
  • 不同包路径下的类由不同的类加载器加载
  • jvm懒加载,根据需要去动态加载
  • 父加载器不是父类,双亲委托:自下而上,先挨个找缓存,到了顶层缓存中还没有,就开始初始化,从各自对应负责的包路径下查找,有就创建,没有给就子加载器加载
  • 加载之后存在缓存当中
  1. 加载的结果
  • 将class文件加载在内存中。
  • 将静态数据结构(数据存在于class文件的结构)转化成方法区中运行时的数据结构(数据存在于JVM时的数据结构)。
  • 在堆中生成一个代表这个类的java.lang.Class对象,作为数据访问的入口。
  1. 核心方法: loadClass、 findLoadedClass、parent.loadClass、findBootStrapClass、findClass

自定义类加载器

实现自定义class文件加载路径,实现,class文件包路径的限制

https://www.cnblogs.com/gdpuzxs/p/7044963.html

实现逻辑:写一个classloader类(构造函数里面需要传入包真实的路径),重写findClass方法,

public class MyClassLoader extends ClassLoader{
    public MyClassLoader(String classpath) {
        this.classpath = classpath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte [] classDate=getDate(name);
            
            if(classDate==null){}
            
            else{
                return defineClass(name,classDate,0,classDate.length);
            }
            
        } catch (IOException e) {
            
            e.printStackTrace();
        }
        
        return super.findClass(name);
    }
}

实现类的每次重新加载,实现热加载

  1. 本来重写 findLoadedClass()即可,直接返回null,实现热加载,但是ClassLoader把该方法设置为final了,不希望去破坏这个规则
  2. 所以直接通过重写过的findClass来实现,相当于在上面的基础上做修改,findClass的路径为当前路径,每次loadClass,直接调用findClass方法即可,虽然只能修改本地的class类
  3. findClass需要defineClass来最终把字节码文件加载进内存当中,JVM默认相同的类加载器不能加载相同全路径的类,所以每次重新加载的时候需要new一个自定义加载器,否则会报错
    String currentPath=Class.class.getClass().getResource("/").getPath()

    MyClassLoader myClassLoader=new MyClassLoader(currentPath);
    Class c=myClassLoader.findClass("com.test.Action.Test");
    
    MyClassLoader myClassLoader2=new MyClassLoader(currentPath);
    Class c2=myClassLoader2.findClass("com.test.Action.Test");

tomcat的类加载模型

  • tomcat本身也是一个依赖JDK的应用
  • tomcat/bin目录下有自己的jar包需要AppClassLoader加载:tomcat-juli.jar、bootstrap.jar等等
  • 每个独立的应用有自己的class路径,通过WebappClassloader加载,应用也依赖JDK的加载,所以应用的类加载机制:缓存加载-->AppClassLoader JDK系统加载-->自己加载-->父类加载
  1. 核心加载器
  • CommonClassLoader(默认父加载器为AppClassLoader)。加载一些tomcat/lib下面的jar包,servlet-api.jar、jsp-api.jar等
  • catalinaClassLoader(默认是空,有需要的话需要自己配置)
  • sharedClassLoader(默认是空,有需要的话需要自己配置)
  • WebAppClassLoader(tomcat下 WebRoot/应用程序/WEB-INF/lib 和 class包下的类
  1. 层级结构
  • tomcat下每个应用程序都有一个独立的类加载器,WebAppClassLoader,因为不同应用程序的类不能乱加载,更不能公用啊。
  • 但是有一些通用的类,比如JUnit、Log4j类,是不同应用程序公用的类,所以有sharedClassLoader出场,可以设置路径来实现这个类加载器,从而实现不同应用程序共同加载一些通用工具类
  • 再上一层就是CommonClassLoader:下面由shardClassLoader和CatalinaClassLoader,一个是所有应用程序,一个是tomcat容器的扩展类加载器
  • 再上一层就是AppClassLoader了,就是传统的模式往上走了
  1. 加载逻辑(源码 org.apache.catalina.loader.WebappClassLoader#loadClass)
    tomcat的类加载机制是违反了双亲委托原则的:先本地缓存查找,再全局缓存查找,再系统加载,再自己加载,最后再父加载器加载
  • 先在本地缓存中查找是否已经加载过该类(clazz = findLoadedClass0(name))
  • 再查询JVM缓存中查找是否已经加载过该类( clazz = findLoadedClass(name))
  • 让系统类加载器(AppClassLoader)尝试加载该类,主要是为了防止一些基础类会被web中的类覆盖(tomcat bin下包)(clazz = system.loadClass(name))
  • web应用的类加载器将自行加载(findClass),这里也违背了双亲 (clazz = findClass(name);)
  • 最后还是加载不到的话,则委托父类加载器(Common ClassLoader)去加载。(clazz = Class.forName(name, false, parentLoader);)

反射和Spring IOC

  • 反射是运行期编译,只有执行到这个方法,确定了参数:类名的时候才编译出对应的class文件,再加载到内存当中
    Class tc = Class.forName("com.java.dbtest.TestConnection");
  • CGLIB也是运行期编译,Enhancer类继承代理类,拦截相应的方法,实现代理
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容