两个Web应用之间怎么共享库类,并且不能重复加载相同的类?
双亲委派机制的各子加载器都能通过父加载器去加载类,于是考虑把需共享的类放到父加载器的加载路径。
应用程序即是通过该方式共享JRE核心类。
Tomcat搞了个类加载器SharedClassLoader,作为WebAppClassLoader的父加载器,以加载Web应用之间共享的类。
若WebAppClassLoader未加载到某类,就委托父加载器SharedClassLoader去加载该类,SharedClassLoader会在指定目录下加载共享类,之后返回给WebAppClassLoader,即可解决共享问题。
如何隔离Tomcat本身的类和Web应用的类?
兄弟关系:两个类加载器是平行的,它们可能拥有同一父加载器,但两个兄弟类加载器加载的类是隔离的。
于是,Tomcat搞了CatalinaClassLoader,专门加载Tomcat自身的类。
问题是,当Tomcat和各Web应用之间需要共享一些类时该怎么办?
共享依旧靠父子关系。
再增加个CommonClassLoader,作为CatalinaClassLoader和SharedClassLoader的父加载器。
CommonClassLoader能加载的类都可被CatalinaClassLoader、SharedClassLoader 使用,而CatalinaClassLoader和SharedClassLoader能加载的类则与对方相互隔离。WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。
==========================================================================
JVM默认情况下,若一个类由类加载器A加载,则该类的依赖类也由相同的类加载器加载。
比如Spring作为一个Bean工厂,它需要创建业务类的实例,并且在创建业务类实例之前需要加载这些类。Spring是通过调用Class.forName来加载业务类的,我们来看一下forName的源码:
public static Class<?> forName(String className) {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
会使用调用者,即Spring的加载器去加载业务类。
Web应用之间共享的jar可交给SharedClassLoader加载,以避免重复加载。Spring作为共享的三方jar,本身由SharedClassLoader加载,Spring又要去加载业务类,按照前面那条规则,加载Spring的类加载器也会用来加载业务类,但是业务类在Web应用目录下,不在SharedClassLoader的加载路径下,这该怎么办呢?
于是有了线程上下文加载器,一种类加载器传递机制。因为该类加载器保存在线程私有数据里,只要是同一个线程,一旦设置了线程上下文加载器,在线程后续执行过程中就能把这个类加载器取出来用。因此Tomcat为每个Web应用创建一个WebAppClassLoader类加载器,并在启动Web应用的线程里设置线程上下文加载器,这样Spring在启动时就将线程上下文加载器取出来,用来加载Bean。Spring取线程上下文加载的代码如下:
cl = Thread.currentThread().getContextClassLoader();
在StandardContext的启动方法,会将当前线程的上下文加载器设置为WebAppClassLoader。
启动方法结束时,会恢复线程的上下文加载器:
Thread.currentThread().setContextClassLoader(originalClassLoader);
这是为什么呢?
线程上下文加载器其实是线程的一个私有数据,跟线程绑定,这个线程完成启动Context组件后,会被回收到线程池,之后被用来做其他事情,为了不影响其他事情,需恢复之前的线程上下文加载器。
优先加载web应用的类,当加载完了再改回原来的。
线程上下文的加载器就是指定子类加载器来加载具体的某个桥接类,比如JDBC的Driver的加载。
=================================================================
最后
总的来说,面试官要是考察思路就会从你实际做过的项目入手,考察你实际编码能力,就会让你在电脑敲代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在和面试官说项目说技术时的话就好了
代码,看你用什么编辑器、插件、编码习惯等。所以我们在回答面试官问题时,有一个清晰的逻辑思路,清楚知道自己在和面试官说项目说技术时的话就好了
[外链图片转存中…(img-kbXf0Z0e-1718019673914)]
[外链图片转存中…(img-RqAwaTEu-1718019673915)]