00:00
好,那在谈到双清品牌机制的这个优点和缺点之后啊,咱们来看一看破坏双清品牌机制的一些行为,那因为呢,我们提到了这个优点呢,是非常明确的,当然这个缺点的话呢,也是我们在实际开发这个场景当中,是我们必须要解决的问题。对吧,我们确实有很多场景下呢,需要使用这个上层的类的加载器使用,呃,具体加载的那些类的那个实现,那些实现呢,是由下层类的加载器所加载的,那我们要避开这个单向调用的一个行为,那怎么办呢?这就提到了一些破坏行为是吧,那这些破坏行为呢,典型的是有三种场景,或者换句话说,按照这个时间的先后顺序呢,那就是历史上呢出现了这三次。哎,是这样子的,好,那么在面试当中呢,有的时候也经常会问到说破坏双擎派机制的这个行为有哪些,这个大家呢,诶把大把这呢也当成像一个常识一样啊,我们熟悉熟悉。好,那首先的话呢,我们说一下第一次破坏双亲委派机制的这个行为,那我们知道双亲委派机制啊,咱们是在JDK1.2的时候呢才引入的,那自然而然,那就意味着我们不满足这个在JDK1.2之前是不是就不满足这个双擎排模型啊。
01:16
对吧?哎,这是很自然的事情,在这里边我们又提到了关于这个类加载器的这个概念和使用,包括呢,这个抽象类club loader呢,我们在JK1.0的时候呢,就已经有了,咱们前面呢,刚开始介绍的时候呢,不也说过这个事儿,对吧?诶一开始呢就有了,那这个class呢,你想它是个抽象类,那我们大家做开发的你都知道,只要你看到一个类似抽氧类,我们第一反应呢,就是它不能实例化,然后呢,我们需要提供它具体的子类,对吧?那我们要提供子类的话呢,就会涉及到重写这个load class方法。那你里边呢,你想怎么加载你就怎么加载。那自然而然的,呃,这个1.2之前呢,那都不满足双性派机制嘛,对吧,好了,那现在呢,这个事儿其实很好说啊,关键呢,我们要理解这个点,就是下边这个事儿呢,这个大家要清楚什么事呢?你看啊,咱们这个1.2的时候呢,咱们引入了一个双擎语派机制,咱们把这个load class呢,里边是不是体现了那个双擎品牌基制那个代码就都写上了,对吧,咱们前面已经说过了啊,那写上之后呢,那这时候你再看之前的那些在1.2之前写的那些代码,比如说我们自己提供了一个class load的一个这个子类,然后咱们把这个load class方法呢,也给重写了。
02:26
这样这样稍微画个图吧,你想想啊,这个这是class loader里边呢,有这个load class这个方法呢,JDK1.2之前呢,肯定是不满足双品牌机制的,对吧,然后1.2之后呢,满足了这个呢,注意里边体现了这个双性品牌机制,但是现在的话呢,这个你还看以前你1.2之前写的这个代码,我们提供了一个叫sub。这个class具体的一个此类,那你要是重写了这个load class方法的话呢,相当于这个方法呢,对负类的这个有双擎I机这个方法又是个覆盖了,那因覆盖呢,在这块是不是照样又不体现这个双节排机制了。
03:03
啊,那事实上呢,也确实这样,但是呢,呃,避免让用户以后呢还这样去写,尽量的去遵循双擎派怎么办呢?诶这里就提到咱们后边要讲的自定义类ATE加载器的这个两种不同的方式,建议呢,以后用户再去写的话呢,就不要呢去这个重写这个load class方法了,而我们在这个load class class方法里边呢,除了双节语派那些逻辑之外呢,我们定义的那个叫find的class是吧?叫find的class,建议呢,用户你把这个饭的class呢,你呢去重写一下,那这样的话呢,我们覆盖也只是覆盖负类中的这个饭的class,那仍然呢,调用的时候我们用的是load class,仍然满足双键排机制。啊,这是我们说建议用户这样去实现,那下边呢,我们要是去定义的话呢,呃,那咱们也就这样做,去重写这个find class,不要尽量不动这个load class这个方法啊行,这个呢,就是我们说的第一次破坏行为,其实这句话呢,一说就完了,就是1.2之前呢,就是一个破坏的,对吧,因为那时候还没有啊,那接下来呢,我们看一下这个第二类这个破坏行为。
04:03
这个所谓的第二类破坏行为呢,实际上就是针对于咱们刚才呢,提到了这个弊端的问题。对吧,哎,针对这个弊端问题的一个解决,那这呢就提到了这个破坏行为二。这儿呢,提到了叫线程上下文的类的加载器,那它呢是我们解决的方案。哎,这是咱们解决的方案,你看我这里边写的这个文字挺多,那我们整个呢,给大家呢,哎捋一下啊,这个事儿首先的话呢,我们明确这个双节派机制呢,它设计的一个缺陷是吧,缺陷这个它它它是有这个缺陷导致的是吧?那它目前这个行为是什么呢?就是越基础的类啊,由越上层的类的加载器呢,进行加载啊,这咱们认为是没有问题的是吧?但是呢,如果这个基础的类呢,又要回调用户写的这个代码,那该怎么办呢?那就是我们上层的这个接口由引导类加载器呢进行加载,但是这个接口具体的实现,那需要由系统类加载器进行加载,那我们现在引导类加载器没法调怎么办呢。
05:02
怎么办呢?怎么呢,怎么办呢,说启动类加载器绝不可能认识和加载,就是你这些接口的具体实现的这个代码怎么办?哎,这里边儿这个呃具体的这个呃,子类的提供的这些代码呢,咱们这起了个名字叫SPI。啊叫SPI,就下上面的这一段描述哈,比如说呢,咱们这个jdi这个服务,这个服务呢,已经是Java的这个标准服务了,它的这个核心API呢,是由咱们这叫什么启动类加载器进行加载的,对吧?看启动类加载加载的,但是具体的这一套接口里边这个实现就是我们通常把这个RT点炸包当中提供的具体的啊,这个供外部服务,这个可由应用类这个应用层呢,具体实现的这个接口我们称为呢叫spi。就是这些核心API的具体的实现的这个集合,我们称为呢叫SPI了,那你这个SPI的话呢,显然的话呢,我们说天然的就不能由启动类加载器呢进行加载了,那应该怎么办?这里边儿呢,引入了一个叫不太优雅的一个设计,叫线程上下文的一个加载器。
06:03
哎,线程上下文的一个类的加载器。啊嗯,这个还提到这个内在加载器,那这个呢,是不是,呃,跟我们一开始提的这个结构又不一样了呢。呃,咱们提到这个结构不就是这样几个吧,那你线程上下文的类的加载器,这属于谁呢?那我们说呢,默认情况下呢,这个线程上下文的类的加载器,它属于叫哎应用程序类加载器,或者叫系统类加载器啊,就是它这个咱们在前面呢,是不是看那个源码的时候呢,其实看到过对吧,咱们当时看到的是不是这个叫诶launcher啊。哎,Launcher你看找到这个launcher呢,我们进来。进来之后呢,咱们找这个它的构造器,构造器里边这个呢,是我们的扩展类加载器,这呢是我们的这个叫呃应用程序类加载器,对吧?然后这呢是一个loader,然后在下边这块你看点current th.set contact class将上下文的类的加载器,拿我们这个呃应用程序类或者叫系统类加压器呢,进行了一个复制,所以默认情况下呢,线成上下文的类加载器呢,就是咱们的系统类加器。
07:09
哎,就是这样个情况,好,先明确这样一个概念。嗯,再回过来啊。啊,先明确这样一个概念,然后呢,有了这个线程商业文类的加载器之后呢,这个说程序呢,就可以做一些舞弊行为啊,一些舞弊行为咱们先举一个生活中的例子啊,你比如呢,这是公司的这个,哎,普通员工是吧。这呢是公司的这个中层,哎,然后呢,再往上呢,就是公司的这个高层啊,董事会是吧,这样的一个层级,那正常我们说呢,这个越高级的这些事儿啊,大的这个决定是不是都应该由上层来做,对吧?比如说呢,这个高层,比如说维护呢,跟这个哎行业政府的这个关系啊是吧?哎这块呢,是由这个高层来维护的,然后这个中层的话呢,比如去维护这个,诶行业的一些同行的一些信息的了解啊,哎,对吧?哎,他维护同行的,而后我们这个,呃,最下边这一层普通员工呢,就是做一些具体的这个事务了。
08:01
要具体些数,那正常来讲呢,就是一个,比如一个普通员工一看呀,有个事儿来了,这事儿一看他干不了啊,交给他的中层,中层也干不了,交给他的这个在上层去操作,就有点儿像咱们说那叫双擎美派模型,对吧,那现在呢,出来一个事儿就是这个,诶公司的这个高层突然一天早上一来公司一打开电脑,完了,电脑坏了。启动不了了,哎呀,这怎么办呢?正常来讲这个告诫的事应该自己做是吧,但是自己确实也搞不定,哎,这时候是不是还偷偷的得告诉我们这个一个普通员工,呃,后后这个比如说后勤的,或者叫这个运营部门说呢,哎呀,这个来一个咱们的同事来帮我把电脑修一修是吧,就是这个高层的搞不定,那需要呢,就是由这个下边的这个具体的我们说底层的这个类的加载系统去提供一些具体的操作了。就有点像呢,说你说你核心的API啊,由这个比如说就g Di这里边的核心的API,你说呢,有你这个引道里加载器去下载,但是你的具体实现呢,就得需要用这个,呃,系统为加载性能去加载,那你上层呢,现在想用下层默认用不了怎么办呢?咱们整一个舞弊行为是吧?哎,这个称为舞弊行为了啊,就是一个没办法的办法,我现在呢定一个叫线成上下文的类的加载器,哎,当我这个引导类加载器想用具体下边具体实现的时候呢,我呢就委托给这个上下文的类的加载器,那上下文的类的加载器呢,再去调用我们具体的这个叫那系统类加载器。
09:24
哎,来实现呢,对这个功能的一个调用。啊,就是这样的行为,那这呢,是不是显然呢,是违背了我们双性语派模型的一般性原则呀。对吧,哎,违背了原则,哎,但是呢,我们也只能这样的去实现。啊OK,那相当于呢,这个线程上下文的内在加载器,它其实作为一个中介,是作为一个中介啊来体现的,好,这呢就是我们说的第二次的这个破坏行为。啊,这就过了,然后接着呢,我们来看一下这个第三次的一个破坏行为。这个破坏行为呢,是由于那用户呢,对程序动态性的一个追求啊导致的,这里边儿呢,提到两个词,一个呢叫代码热替换啊,一个呢叫模块热部署。
10:06
啊,这个说白了啊,什么叫这个代码的热极化,或者叫模块的这个热部署呢,其实就是希望咱们这个Java应用程序呢,就像咱们这个电脑这个外设一样啊,这个大家比如说这是一台电脑这个外设的话呢,是不是具体有这个USB这个口是吧?我们连接上这个鼠鼠标啊,U盘呀,或者这个键盘呀,是吧,这都是属于这个外部的这个设备,那这个外部设备呢,我们发现呢,咱们不需要重启电脑,是不是直接插上就可以用啊。对吧,那你用的过程当中,突然这个鼠标呢,你发现坏了出来之后呢,我们把这个鼠标是不是拔下来,你再插上一个鼠标,新的一个鼠标发现呢,诶正常还就可以进行编辑了。这呢,就类似于我们说的,这叫热部署。啊,当然有同学也想说说我这个电脑,我把这个鼠标拔了以后呢,我再插上之后说呢,哎,这时候没有实现热部署,需要重启电脑,重启就重启呗,哎,重启电脑啊花上你要是快的话呢,这个固态硬盘十几秒就搞定了是吧,慢的呢,一两分钟也肯定能重启,好圣,那也没什么大不了的是吧,不用热部署也没关系。
11:07
啊,这个呢,你个人电脑其实还好,但是这时候你想,如果是我们这个企业的这个项目系统,大家你想想我们把这个系统呢,部署在这个服务器上了,然后现在呢,我们想实现相关功能的一个替换啊,相关模块替换,那如果说你要需要把这个服务给停掉是吧,整个这个项目系统给它关掉,然后呢,部署好以后呢,再重启,哇,那你们可以想象,首先的话呢,服务要停掉的话呢,这个为了不影响用户访问,你是不是还得有这个呃,备份的这个系统去启动,对吧,这是其一,其二呢,这个系统呢,呃,你要是给他在启动的时候有大量的这个一些加载呢,需要重新实现,那这个时间呢,是花的很长的。那显然呢,不是一个特别好的方式是吧,那如果说我们对于这个线上的系统能够实现这个代码的热替换和模块的热部署的话呢,那简直呢是一个完美的解决方案啊,就像我们这个鼠标呢,直接你切换一个就完事了是吧?啊,这是非常好的啊。
12:05
好,那这里边呢,就提到了这个MM呢,主导的这个呃,GSR291的这样一个项目,那我们也称为呢叫OS cii啊,那要提到他之前呢,其实还有一段历史啊,就是关于这个模块化这个知识的话呢,其实在这个扎坝社区啊,2008年的时候,其实就有一次这个战役是吧?诶当时呢,也是这个散公司,或者我们称为呢叫Oracle公司啊,其实呢,它也是想实现这个具体的模块化,也提供了提供了相应的这个GS的一些提案啊,但是呢,最后呢,呃,由IBM主导的这个GS2这个提案呢,就是获得成功。那也就是说呢,关于这个模块热部署方面呢,这个IBM的这个OSAI啊,其实是这个形成了这个事实上的一个标准啊,把这个Oracle跟这个萨姆斯啊按在地上摩擦是吧。那么在这个扎拉酒的时候啊,这个。Oracle公司呢,这个就这叫什么呀,不服气是吧,在扎阿九的时候呢,又引入了这个叫T啊这样的一个项目。
13:02
啊,这个大家呢,你要关注这个新得性的话呢,应该知道这个JSO的模块化啊,在这个JAVA9引入这个JSO的时候呢,渐渐的才形成了这个Java实质上的一个模块化的一个标准,但是呢,呃,由于这个IBM的OS cii呢已经是比较成熟了,所以呢,呃,在JSO这个相关的个项目使用的时候呢,也尽量的是避开OS cii在运行社会上的一些优势。啊是这样的一些问题啊,那咱们这呢,就主要呢,给大家来谈一谈这个IBM的这个osci啊,它呢实现这个热部署,那这里边呢,关于这个你看这也提到了,在每一个模块啊,它称为呢叫帮啊,每个模块当中都有一个自己的类的加载器。哎,都有一个自己的类的加载器,那么此时的这一类的加载器呢,就不再满足咱们提到的这叫树状结构啊,就是你上层下层是吧,这呢是进一步发展为一个叫网状结构,那还有这个同级的类的加载器。那具体的这个搜索细节呢,咱们不具体展开来说啊,那主要呢,我们从大方向来看,哎,Java甲新闻开头的我们由傅雷加去加载,否则呢,委派给名单中的这个类啊,委派呢,呃,给这个负类的类的加载器加载,在这块呢,仍然体现了这种这个树状的这个结构,就是涉及到双性委派模型,然后在后边呢,这块就涉及到同类的啊,同层级的类的加载器的一个加载,那就构成了,诶本身呢是一个竖状的结构,然后我们现在又横状的结构了,那这这不就是一个网状结构吗?
14:23
OK吧,好这呢,就是我们提到的这个叫第三次的一个破坏行为啊,那这里边儿呢,关于这个破坏呢,我们应该加上这个引号。那这个被破坏呢,我们说不是说它带有这个贬义的意思,只是说呢,我们不满足那双减排机制而已。那我们也理由有理由呢,相信它其实是对于我们原有的规则的一种创新,对吧?那像这个热部署的话,当然是非常好的一件事情啊,当然呢,也有行业的一些诟病啊,说这个热部署呢,带来额外的高复杂度是吧?哎,存在一些这个争议啊,但是呢,呃,确实OS呢这类的加载器的一个运用啊,在具体实际开发当中,场景的一个实现上呢,还是非常不错的行,那关于呢,破坏机制的三种体现啊,这个大家呢,作为一个常识啊,需要熟悉。
15:10
主要呢,我们接触相对偏多的呢,是这个第二种的一个方式对吧?啊,这个在具体的像这个大家操作像GDBC啊,像g Di啊啊JCE啊啊等等这样的场景下呢,其实我们都涉及到了第二种行为的这种破坏。啊,使用呢,现成商业文类的加载器来实现。好。
我来说两句