前言
最近尝试手写一个简单的Tomcat,但在类加载这一块有点模糊,,于是有了下面的猜想:
java项目是如何被加载已经如何被执行的,,通过资料得知靠的是loader模块,并且tomcat与Java项目共享同一JVM资源(现需要了解JVM,目前猜想:Tomcat与java项目可以看作同一个Java项目,一起加载进JVM中,,Tomcat与Java项目可以互相调用)
后面去了解了类加载器后发现猜想出错了,如果Tomcat的依赖包与Java项目没有存在依赖冲突,我的猜想还能接受,但是真的把看作一个项目是会出问题的,而Tomcat的做法很好的解决了这个问题。
类加载器
因为没有过多的了解类加载器,导致了理解上的偏差,所以先要了解类加载器:类加载器分为三种:bootstrapclassloader,extclassloader,appclassloader,除此之外还可以自定义类加器:你可以继承classloader类,重写核心方法来实现自己的类加载器,只能说java的设计者在对灵活性与扩展性方面做的真的很好,这些都考虑到了,所以类加载器并没有封装到JVM内部,而是在外部实现的,并且可供开发者自行设计。
双亲委派与打破双亲委派
提到类加载器,就不得不提里面的一个重要机制:双亲委派机制,它的实现其实并不复杂你可以查看classloader类的源码,里面就能看到双亲委派机制实现代码,用简单的逻辑解决了类加载重复,以及可能会被开发者篡改源码的风险这两大问题,膜拜大佬,下面是双亲委派机制源码:
1.入口
2.实现双亲委派
虽然双亲委派设计很好,可是也得根据实际情况,而tomcat是一个web服务器,它可能需要部署多个应用,那么每个应用都会有各自的依赖,如果是相同jar包的不同版本,这时,双亲委派就成了问题的原因,这个时候就需要打破双亲委派,如何打破?实现自己的类加载器,jvm识别不同的类靠的是全限定类名与类加器,不同的类加载器加载的类必定不相同,比如:Java的核心类库:Integer,如果自己写一个一模一样的,jvm会用吗?那必不会,因为双亲委派机制的存在,它会发现String类已经由bootstrapclassloader加载器加载过了,而自己编写的代码是由appclassloader加载的,双亲委派决定了父类的优先级更高,而且这个双亲委派用Java是无法打破的,因为它不是由java语言编写,由C/C++编写。通过实现自定义类加载器,打破了双亲委派机制,实现了应用间的依赖隔离,但是,需要打破全部双亲委派吗?比如一些共有的依赖,所有web程序都会共用的依赖也需要打破吗?除了bootstrapclassloader无法打破之外,可能还会存在一些需要共用的依赖可以不打破。但是双亲委派的设计是毋庸置疑的,任何设计都不可能做到十全十美。