日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Tomcat - 模拟Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离

發(fā)布時(shí)間:2025/3/21 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Tomcat - 模拟Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • Pre
  • Tomcat要解決什么問題?
  • Tomcat違反了雙親委派機(jī)制?
  • 模擬Tomcat的webappClassLoader加載自己war包應(yīng)用內(nèi)不同版本類實(shí)現(xiàn)相互共存與隔離
  • Tomcat加載機(jī)制小結(jié)

Pre

Tomcat - 都說Tomcat違背了雙親委派機(jī)制,到底對不對?

JVM-白話聊一聊JVM類加載和雙親委派機(jī)制源碼解析

JVM - 實(shí)現(xiàn)自定義的ClassLoader就是這么簡單


Tomcat要解決什么問題?

作為一個(gè)Web容器,Tomcat要解決什么問題 , Tomcat 如果使用默認(rèn)的雙親委派類加載機(jī)制能不能行?

  • 我們知道Tomcat可以部署多個(gè)應(yīng)用,不同的應(yīng)用程序可能會(huì)依賴同一個(gè)第三方類庫的不同版本,不能要求同一個(gè)類庫在同一個(gè)服務(wù)器只有一份,因此要保證每個(gè)應(yīng)用程序的類庫都是獨(dú)立的,保證相互隔離 .

    舉個(gè)例子 假設(shè)APP1 使用的是 Spring4 , APP2 使用的是Spring5 , 毫無疑問 Spring4 和 Spring 5 肯定有 類的全路徑一樣的類吧,如果使用雙親委派 ,父加載器加載誰?

  • 部署在同一個(gè)web容器中相同的類庫相同的版本可以共享, 比如jdk的核心jar包,否則,如果服務(wù)器有n個(gè)應(yīng)用程序,那么要有n份相同的類庫加載進(jìn)虛擬機(jī)。

  • web容器 自己依賴的類庫 (tomcat lib目錄下),不能與應(yīng)用程序的類庫混淆。基于安全考慮,應(yīng)該讓容器的類庫和程序的類庫隔離開來。

  • web容器要支持jsp的修改, jsp 文件最終也是要編譯成class文件才能在虛擬機(jī)中運(yùn)行, web容器需要支持 jsp 修改后不用重啟 ,就是熱加載的功能。

  • 結(jié)合上面的4個(gè)問題,我們看下雙親委派能不能支持?

    第一個(gè)問題,如果使用默認(rèn)的類加載器機(jī)制,肯定是無法加載兩個(gè)相同類庫的不同版本的,如果使用雙親委派,讓父加載器去加載 ,不管你是什么版本的,只要你的全限定類名一樣,那肯定只有一份,APP 隔離 無法滿足

    第二個(gè)問題,默認(rèn)的類加載器是能夠?qū)崿F(xiàn)的,很好理解嘛, 就是雙親委派的功能,保證唯一性。

    第三個(gè)問題和第一個(gè)問題一樣。

    第四個(gè)問題, 要怎么實(shí)現(xiàn)jsp文件的熱加載呢? jsp 文件其實(shí)也就是class文件,那么如果修改了,但類名還是一樣,類加載器會(huì)直接取方法區(qū)中已經(jīng)存在的,修改后的jsp是不會(huì)重新加載的。那么怎么辦呢?可以直接卸載掉這jsp文件的類加載器 .當(dāng)一個(gè)jsp文件修改了,就直接卸載這個(gè)jsp類加載器。重新創(chuàng)建類加載器,重新加載jsp文件。 源碼詳見: org.apache.jasper.servlet.JasperLoader


    Tomcat違反了雙親委派機(jī)制?

    Bootstrap|System|Common/ \Webapp1 Webapp2 ...

    也不盡然,核心的Java的加載還是遵從雙親委派 。

    Tomcat中 各個(gè)web應(yīng)用自己的類加載器(WebAppClassLoader)會(huì)優(yōu)先加載,打破了雙親委派機(jī)制。加載不到時(shí)再交給commonClassLoader走雙親委托 .


    模擬Tomcat的webappClassLoader加載自己war包應(yīng)用內(nèi)不同版本類實(shí)現(xiàn)相互共存與隔離

    我們基于JVM - 實(shí)現(xiàn)自定義的ClassLoader就是這么簡單

    package com.gof.facadePattern;import java.io.FileInputStream; import java.lang.reflect.Method;/*** @author 小工匠* @version v1.0* @create 2020-06-11 23:09* @motto show me the code ,change the word* @blog https://artisan.blog.csdn.net/* @description**/public class MyClassLoaderTest {static class MyClassLoader extends ClassLoader {private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}private byte[] loadByte(String name) throws Exception {name = name.replaceAll("\\.", "/");FileInputStream fis = new FileInputStream(classPath + "/" + name+ ".class");int len = fis.available();byte[] data = new byte[len];fis.read(data);fis.close();return data;}protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {if ("com.gof.facadePattern.Boss1".equals(name)){c = findClass(name);}else{// 交由父加載器去加載c = this.getParent().loadClass(name);}}if (resolve) {resolveClass(c);}return c;}}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] data = loadByte(name);//defineClass將一個(gè)字節(jié)數(shù)組轉(zhuǎn)為Class對象,這個(gè)字節(jié)數(shù)組是class文件讀取后最終的字節(jié)數(shù)組。return defineClass(name, data, 0, data.length);} catch (Exception e) {e.printStackTrace();throw new ClassNotFoundException();}}}public static void main(String args[]) throws Exception {//初始化自定義類加載器,會(huì)先初始化父類ClassLoader,其中會(huì)把自定義類加載器的父加載器設(shè)置為應(yīng)用程序類加載器AppClassLoaderMyClassLoader classLoader = new MyClassLoader("D:/artisan");//D盤創(chuàng)建 artisan/com/gof/facadePattern 目錄,將Boss類的復(fù)制類Boss1.class丟入該目錄Class clazz = classLoader.loadClass("com.gof.facadePattern.Boss1");Object obj = clazz.newInstance();Method method = clazz.getDeclaredMethod("sout", null);method.invoke(obj, null);System.out.println(clazz.getClassLoader() );System.out.println();MyClassLoader classLoader1 = new MyClassLoader("D:/artisan1");//D盤創(chuàng)建 artisan1/com/gof/facadePattern 目錄,將Boss類的復(fù)制類Boss1.class丟入該目錄Class clazz1 = classLoader1.loadClass("com.gof.facadePattern.Boss1");Object obj1 = clazz1.newInstance();Method method1 = clazz1.getDeclaredMethod("sout", null);method1.invoke(obj1, null);System.out.println(clazz1.getClassLoader() );} }


    為了好區(qū)分 我們把Boss1 的類 ,sout方法的輸出稍微調(diào)整下,以示區(qū)別。

    應(yīng)用中的Boss1 無需刪除

    同時(shí)模擬第二個(gè)應(yīng)用, 在D盤創(chuàng)建 artisan1/com/gof/facadePattern 目錄,將Boss類的復(fù)制類Boss1.class丟入該目錄

    基于以上前置條件,得出如下結(jié)論

    我們通過上面的示例模擬出了同一個(gè)JVM內(nèi), 分別使用不同的類加載器(new 出來的)去加載不同classpath下的類,而避免了走雙親委派,去模擬tomcat的類加載機(jī)制

    通過結(jié)論可以得出在同一個(gè)JVM內(nèi),兩個(gè)相同包名和類名的類對象可以共存,是因?yàn)樗麄兊念惣虞d器不一樣。

    所以看兩個(gè)類對象是否是同一個(gè),除了看類的包名和類名是否都相同之外,還需要他們的類加載器是否相同


    Tomcat加載機(jī)制小結(jié)

    當(dāng)tomcat啟動(dòng)時(shí),會(huì)創(chuàng)建幾種類加載器:

  • Bootstrap 引導(dǎo)類加載器 : 加載JVM啟動(dòng)所需的類,以及標(biāo)準(zhǔn)擴(kuò)展類(位于jre/lib/ext下)

  • System 系統(tǒng)類加載器 : 加載tomcat啟動(dòng)的類,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下


  • 4. webapp 應(yīng)用類加載器: 每個(gè)應(yīng)用在部署后,都會(huì)創(chuàng)建一個(gè)唯一的類加載器。該類加載器會(huì)加載位于 WEB-INF/lib下的jar文件中的class 和 WEB-INF/classes下的class文件。

  • Common 通用類加載器:加載tomcat使用以及應(yīng)用通用的一些類,位于CATALINA_HOME/lib下,比如servlet-api.jar

  • 總之 當(dāng)應(yīng)用需要到某個(gè)類時(shí),則會(huì)按照下面的順序進(jìn)行類加載:

    1 使用bootstrap引導(dǎo)類加載器加載 (JVM 的東西 )

    2 使用system系統(tǒng)類加載器加載 (tomcat的啟動(dòng)類Bootstrap包)

    3 使用WebAppClassLoader 加載 WEB-INF/classes (應(yīng)用自定義的class)

    4 使用WebAppClassLoader 加載在WEB-INF/lib (應(yīng)用的依賴包)

    5 使用common類加載器在CATALINA_HOME/lib中加載 (tomcat的依賴包,公共的,被各個(gè)應(yīng)用共享的)


    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的Tomcat - 模拟Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。