超好记的类加载+双亲委派模型概念

类加载类的生命周期

类的声明周期经过 加载-连接(验证-准备-解析)-初始化(解析阶段可能动态的在初始化之后)-使用-卸载

加载(与连接交叉进行,仅开始时间有先后顺序)
  1. 通过类全路径名获取该类的二进制流(可从本地/网络/资源包/动态生成)
  2. 该类字节流中的静态存储结构转换为方法区运行时数据结构
  3. 内存中生成该类的Class对象,作为方法区中该类各种数据入口
  4. 除数组类由Java虚拟机创建,其他类的加载(载入类二进制字节流)可使用系统加载或自定义
连接-验证
  1. 验证字节流内信息是否符合Class类文件规范,毕竟加载该字节流可从任何条件符合的地方加载.验证成功后会将该字节流存入方法区
  2. 类元数据语义规范验证,保证符合Java语言规范
  3. 字节码安全性验证,保证该类没有侵入性危害
  4. (解析阶段)符号引用正确性验证,验证类以外引用信息正确合法性验证(类、方法、字段、范围描述符等)
连接-准备

该阶段会为类变量分配内存和设置初始值(零值).当该类变量为final时则会直接给变量赋值(程序设置的值)

连接-解析

将常量池内符号引用(类/方法/类变量等引用)替换为直接引用的过程,将引导符号替换为指针/地址偏移量等

初始化

执行类构造器的过程,初始化类变量和类静态语句块的过程.该类构造器不是程序中定义的构造方法.而是由类静态变量和类静态块组成的<clinit>()方法.且顺序由源文件定义的顺序决定(当有父类则会先将父类初始化掉).
所以就有了这个初始化顺序父类静态成员/块 --> 子类静态成员/块 --> 父类普通成员/块 --> 父类构造函数 --> 子类普通成员/块 --> 子类构造函数. 后面四个阶段根本就不再加载过程中,而是使用过程中.</clinit>

系统ClassLoader介绍

每个ClassLoader加载各自负责的路径下的类.

BootStrap ClassLoader(C++实现,基类加载器) -> ExtClassLoader(拓展类加载器) -> AppClassLoader(应用类加载器)
BootStrapClassLoader负责加载jre\lib基础包类
ExtClassLoader负责加载jre/lib/ext拓展包类(可通过-D java.ext.dirs另行指定目录)
AppClassLoader负责加载自定义应用路径下的类(可通过-D java.class.path另行指定目录)

双亲委派模型

如下图所示,每个ClassLoader是上一个ClassLoader的子Loader(组合机制实现父子级关系,由parent属性指定),每个Loader加载完类会有对应的缓存.双亲委派机制分为向上委托查找以及向下委托加载两部分,用来防止多重名类加载导致基础类覆盖,破坏Java行为问题.

向上委托查找

当加载类请求到ClassLoader上后,该ClassLoader会查找当前加载缓存,当缓存中没有则会将加载请求向上机Loader传递,当传递到Bootstrap后还未从缓存中找到该类则向上委托结束

向下委托加载

当所有ClassLoader均未加载过该类则会进行该类的加载工作,此时加载请求在BootStrapClassLoader上,他会检查自己负责加载路径下是否有该类进行加载,没有则向下委托子Loader在他的加载路径进行查找加载,如果没有则继续向下传递至AppClassLoader结束.

源码来自于java.lang.ClassLoader的loadClass()方法
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
    //检查该类是否有被加载过,是否可以直接从缓存中读取到
    Class c = findLoadedClass(name);
    if(c == null){
        try{
            if(parent != null){
                 // 自己未加载过该类则向上委托父级加载器进行查找加载
                c = parent.loadClass(name, false);
            }else{
                // 没有父类则需要指定由启动类加载器进行查找加载
                c = findBootstrapClassOrNull(name);
            }
        }catch(ClassNotFoundException e){
            // 父类加载器抛出ClassNotFoundException则表示父类加载器无法加载
        }
        if(c == null){
            //经过父类加载器向上委托查找以及向下查找加载至本级均未成功加到该类则自身尝试加载
            c = findClass(name);
        }
        // 解析Class对象
        if(resolve){
            resolveClass(c);
        }
        return c;
    }
}

图片说明

类加载对象ClassLoader了解

上面ExtClassLoader和AppClassLoader均继承自UrlClassLoader.

自定义类加载器

根据上面的类继承机制以及loadClass方法,我们自定义ClassLoader即可继承UrlClassLoader/SecureClassLoader通过实现findClass方法,并在findClass方法中调用defineClass(name,byte,0,byte.length)来实现类定义加载

破坏双亲委派模型

破坏双亲委派模型根据上面代码解析可知我们只需要重写loadClass方法即可(因为他是protected级别的访问限制).但是还是要注意我们只需更改下加载自身实现findClass方法顺序即可,当我们加载其他系统级/未自定义的类还是要交给父级Loader来执行的

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
    //检查该类是否有被加载过,是否可以直接从缓存中读取到
    Class c = findLoadedClass(name);
    if(c == null){
        // 先由自身加载
        c = findClass(name);
        if(c == null){
            try{
                if(parent != null){
                    c = parent.loadClass(name, false);
                }else{
                    c = findBootstrapClassOrNull(name);
                }
            }catch(ClassNotFoundException e){
                // 父类加载器抛出ClassNotFoundException则表示父类加载器无法加载
            }
        }

        // 解析Class对象
        if(resolve){
            resolveClass(c);
        }
        return c;
    }
}

动态字节码技术

笔者这些知识是学习并记录作以加强理解,对这些技术并没有很深入研究.可以参考这篇美团技术团队的文章

Java代码想要被JVM执行就要编译成字节码文件被JVM读取进行解释执行,我们想要对现有功能动态修改就要动态的改变原有的字节码生成新的字节码.
Java中可使用ASM、CGLIB(底层ASM)、BCEL、Javassist等.

ASM

目前最为强大的生成字节码技术之一,可修改类、方法或者重新定义类.核心功能类ClassVisitor、ClassWriter、ClassReader

CGLIB

Spring的AOP技术就使用到了CGLIB,当可以使用动态代理则会优先使用动态代理,否则则会使用CGLIB

热加载

热加载即在不停止服务的前提下,将已修改的类文件替换掉并将其类加载至JVM内存中.IDEA热部署可选择Spring热部署依赖devtools、JRebel热部署插件等.

全部评论

相关推荐

避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
04-17 10:16
门头沟学院 Java
小浪_coder:24届很难找了,马上25的都毕业了还有很多没找到的
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务