亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

java類加載器-Tomcat類加載器

系統 1934 0

  在上文中,已經介紹了 系統類加載器 以及類加載器的相關機制,還自定制類加載器的方式。接下來就以tomcat6為例看看tomat是如何使用自定制類加載器的。(本介紹是基于tomcat6.0.41,不同版本可能存在差異!)

網上所描述的tomcat類加載器

  在網上搜一下“tomcat類加載器”會發現有大量的文章,在此我偷個懶,^_^把網上對tomcat類加載器的描述重說一下吧。

java類加載器-Tomcat類加載器

  • CommonClassLoader:加載的類目錄通過{tomcat}/conf/catalina.properties中的common.loader指定,以SystemClassLoader為parent(目前默認定義是common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar)
  • CatalinaClassLoader?? :加載的類目錄通過{tomcat}/conf/catalina.properties中server.loader指定,以CommonClassLoader為parent,如果server.loader配置為空,則ServerClassLoader 與CommonClassLoader是同一個(默認server.loader配置為空)
  • SharedClassLoader:加載的類目錄通過{tomcat}/conf/catalina.properties中share.loader指定,以CommonClassLoader為parent,如果server.loader配置為空,則CatalinaClassLoader 與CommonClassLoader是同一個(默認share.loader配置為空)
  • WebappClassLoader:每個Context一個WebappClassLoader實例,負責加載context的/WEB-INF/lib和/WEB-INF/classes目錄,context間的隔離就是通過不同的WebappClassLoader來做到的。由于類定義一旦加載就不可改變,因此要實現tomcat的context的reload功能,實際上是通過新建一個新的WebappClassLoader來做的,因此reload的做法實際上代價是很高昂的,需要注意的是,JVM內存的Perm區是只吃不拉的,因此拋棄掉的WebappClassLoader加載的類并不會被JVM釋放,因此tomcat的reload功能如果應用定義的類比較多的話,reload幾次就OutOfPermSpace異常了。
  • JasperLoader:每個JSP一個JasperLoader實例,與WebappClassLoader做法類似,JSP支持修改生效是通過丟棄舊的JasperLoader,建一個新的JasperLoader來做到的,同樣的,存在輕微的PermSpace的內存泄露的情況

以上對個個classloader的作用做了介紹,但請讀者不要搞混淆了,上邊說的個個類加載器只是類加載器的名字,不是類加載類的名字。上邊的圖是看到網上資料的說明繪制的,但是與實際源碼中的結構還是差異挺大的。(沒有研究是不是因為tomcat的版本所致)。下面就詳細介紹下tomcat源碼中類加載器的組織結構。

tomcat源碼中類加載器的結構分析

首先要說明是tomcat默認配置下的情況。那接下來看看tomcat啟動時的類初始化情況,這是BootStrap類的類初始化方法:

??

        private void initClassLoaders() {

        try {

            commonLoader = createClassLoader("common", null);

            if( commonLoader == null ) {

                // no config file, default to this loader - we might be in a 'single' env.

                commonLoader=this.getClass().getClassLoader();

            }

            catalinaLoader = createClassLoader("server", commonLoader);

            sharedLoader = createClassLoader("shared", commonLoader);

        } catch (Throwable t) {

            log.error("Class loader creation threw exception", t);

            System.exit(1);

        }

    }


    

?

可以看到,在創建commonLoader時傳的父類加載器是null。跟蹤下去會發現commonLoader的父類加載器確實是null。有朋友可能想,tomcat在啟動時肯定也要依賴jdk核心庫,parent是null那怎么委托給parent去加載核心庫的類了啊。這里大家不要忘了ClassLoader類的loadClass方法:

      try {

                    if (parent != null) {

                        c = parent.loadClass(name, false);

                    } else {

                        c = findBootstrapClassOrNull(name);//沒有父類加載器時使用bootstrap類加載器

                    }

                } catch (ClassNotFoundException e) {

                    // ClassNotFoundException thrown if class not found

                    // from the non-null parent class loader

                }


    

通過以上initClassLoaders方法我們也能看到catalinaLoader和sharedLoader的父類加載器都是commonLoader,跟上邊圖的類加載器結構符合。但是commonLoader、catalinaLoader和sharedLoader的創建都是依賴tomcat安裝目錄下conf/catalina.properties的配置。默認情況配置是:

  • common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
  • server.loader=
  • shared.loader=

由于server.loader和shared.loader的配置為空,所以其實commonLoader、catalinaLoader和sharedLoader都是指向同一個類加載器實例,看代碼如下:(限于篇幅只貼部分代碼)

       private ClassLoader createClassLoader(String name, ClassLoader parent)

        throws Exception {



        String value = CatalinaProperties.getProperty(name + ".loader");

        if ((value == null) || (value.equals("")))

            return parent;


    

而他們指向那個類加載器類的實例呢?跟蹤到最后我們發現如下代碼:

       StandardClassLoader classLoader = null;

        if (parent == null)

            classLoader = new StandardClassLoader(array);

        else

            classLoader = new StandardClassLoader(array, parent);

        return (classLoader);


    

就是StandardClassLoader的實例,下文再對StandardClassLoader進行源碼講解。

  接下來再看看webappclassloader的創建過程,webappclassLoader是在WebappLoader類中的createClassLoader方法中通過反射實例化的。下邊是源代碼:

          private WebappClassLoader createClassLoader()

        throws Exception {



        Class clazz = Class.forName(loaderClass);//loaderClass="org.apache.catalina.loader.WebappClassLoader"

        WebappClassLoader classLoader = null;



        if (parentClassLoader == null) {

            parentClassLoader = container.getParentClassLoader();

        }

        Class[] argTypes = { ClassLoader.class };

        Object[] args = { parentClassLoader };

        Constructor constr = clazz.getConstructor(argTypes);

        classLoader = (WebappClassLoader) constr.newInstance(args);



        return classLoader;



    }


    

可以看到他的parent是通過調用container.getParentlassLoader()獲得的(如果對tomcat的結構不熟悉,請看這篇 文章 )跟蹤到最后我們發現它調用了ContainerBase的這個方法:

          public ClassLoader getParentClassLoader() {

        if (parentClassLoader != null)

            return (parentClassLoader);

        if (parent != null) {

            return (parent.getParentClassLoader());

        }

        return (ClassLoader.getSystemClassLoader());



    }


    

通過默認配置下debug可以知道最后是返回的systemclassloader,也就是說WebappClassLoader的父類加載器是systemclassloader也就是 上篇文章 說的App ClassLoader。

(由于JasperLoader本人還沒有做分析,先不進行講解了)

tomcat類加載器的實現方式分析

  上文說到了commonLoader、catalinaLoader和sharedLoader都是指向StandardClassLoader的實例,來先看一看StandardClassLoader的源碼實現:

      public class StandardClassLoader

    extends URLClassLoader

    implements StandardClassLoaderMBean {



	public StandardClassLoader(URL repositories[]) {

        super(repositories);

    }



    public StandardClassLoader(URL repositories[], ClassLoader parent) {

        super(repositories, parent);

    }



}


    

有沒有感到你的意外啊,對的就是這么簡單,這跟我 上篇文章 說的最簡單的實現方式一樣。(上篇文章做了解讀,這里不再做說明了)

  我們再來看看webappclassLoader,他的實現類就是org.apache.catalina.loader.WebappClassLoader,此類加載器也是繼承自URLClassLoader,但是它覆蓋了loadClass方法和findClass方法。這個類有三千多行這里就不將代碼全部貼出來了。

      public Class loadClass(String name, boolean resolve)

        throws ClassNotFoundException {



        if (log.isDebugEnabled())

            log.debug("loadClass(" + name + ", " + resolve + ")");

        Class clazz = null;



        // Log access to stopped classloader

        if (!started) {

            try {

                throw new IllegalStateException();

            } catch (IllegalStateException e) {

                log.info(sm.getString("webappClassLoader.stopped", name), e);

            }

        }



        // (0) 檢查WebappClassLoader之前是否已經load過這個資源

clazz = findLoadedClass0(name);

        if (clazz != null) {

            if (log.isDebugEnabled())

                log.debug("  Returning class from cache");

            if (resolve)

                resolveClass(clazz);

            return (clazz);

        }



        // (0.1) 檢查ClassLoader之前是否已經load過

        clazz = findLoadedClass(name);

        if (clazz != null) {

            if (log.isDebugEnabled())

                log.debug("  Returning class from cache");

            if (resolve)

                resolveClass(clazz);

            return (clazz);

        }



        // (0.2) 先檢查系統ClassLoader,因此WEB-INF/lib和WEB-INF/classes或{tomcat}/libs下的類定義不能覆蓋JVM 底層能夠查找到的定義(譬如不能通過定義java.lang.Integer替代底層的實現

        try {

            clazz = system.loadClass(name);

            if (clazz != null) {

                if (resolve)

                    resolveClass(clazz);

                return (clazz);

            }

        } catch (ClassNotFoundException e) {

            // Ignore

        }



        // (0.5) Permission to access this class when using a SecurityManager

        if (securityManager != null) {

            int i = name.lastIndexOf('.');

            if (i >= 0) {

                try {

                    securityManager.checkPackageAccess(name.substring(0,i));

                } catch (SecurityException se) {

                    String error = "Security Violation, attempt to use " +

                        "Restricted Class: " + name;

                    log.info(error, se);

                    throw new ClassNotFoundException(error, se);

                }

            }

        }



        //這是一個很奇怪的定義,JVM的類加載機制建議先由parent去load,load不到自己再去load(見上篇文章),而Servelet規范的建議則恰好相反,Tomcat的實現則做個折中,由用戶去決定(context的 delegate定義),默認使用Servlet規范的建議,即delegate=false

        boolean delegateLoad = delegate || filter(name);



        // (1) 先由parent去嘗試加載,如上說明,除非設置了delegate,否則這里不執行

        if (delegateLoad) {

            if (log.isDebugEnabled())

                log.debug("  Delegating to parent classloader1 " + parent);

            ClassLoader loader = parent;

            

            if (loader == null)

                loader = system;

            try {

                clazz = loader.loadClass(name);

                if (clazz != null) {

                    if (log.isDebugEnabled())

                        log.debug("  Loading class from parent");

                    if (resolve)

                        resolveClass(clazz);

                    return (clazz);

                }

            } catch (ClassNotFoundException e) {

                ;

            }

        }



        // (2) 到WEB-INF/lib和WEB-INF/classes目錄去搜索,細節部分可以再看一下findClass,會發現默認是先搜索WEB-INF/classes后搜索WEB-INF/lib

        if (log.isDebugEnabled())

            log.debug("  Searching local repositories");

        try {

            clazz = findClass(name);

            if (clazz != null) {

                if (log.isDebugEnabled())

                    log.debug("  Loading class from local repository");

                if (resolve)

                    resolveClass(clazz);

                return (clazz);

            }

        } catch (ClassNotFoundException e) {

            ;

        }



        // (3) 由parent再去嘗試加載一下

        if (!delegateLoad) {

            if (log.isDebugEnabled())

                log.debug("  Delegating to parent classloader at end: " + parent);

            ClassLoader loader = parent;

            if (loader == null)

                loader = system;

            try {

                clazz = loader.loadClass(name);

                if (clazz != null) {

                    if (log.isDebugEnabled())

                        log.debug("  Loading class from parent");

                    if (resolve)

                        resolveClass(clazz);

                    return (clazz);

                }

            } catch (ClassNotFoundException e) {

                ;

            }

        }



        throw new ClassNotFoundException(name);

    }


    

?

java類加載器-Tomcat類加載器


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久这里只有精品23 | 一本伊在人香蕉线观新在线 | 四虎永久在线精品国产免费 | 国产精品免费久久久久影院 | 青青久在线精品视频 | 国产欧美日韩图片一区二区 | 久久99精品久久久久久噜噜丰满 | 欧美一级毛片国产一级毛片 | www四虎影视| 免费精品在线视频 | 色综合网站国产麻豆 | 香蕉久久精品 | 中国女人精69xxx | 久草免费资源视频 | 伊人色综 | 91一区二区三区四区五区 | 一区二区日韩 | 亚洲欧洲国产经精品香蕉网 | 99热久热这里只精品 | 亚洲va天堂va国产va久 | www久久只有这里有精品 | a级亚洲片精品久久久久久久 | 国产偷怕自拍 | 国产日本欧美亚洲精品视 | 国产伦一区二区三区免费 | 色偷偷要色偷偷网站视频在线 | 日韩欧美精品有码在线观看 | 性久久久久久久久久 | 日韩一区二区三区在线视频 | 99久久精品免费观看区一 | 好吊妞在线成人免费 | 中文字幕一二区 | 爱爱视频免费在线观看 | 国产又黄又a又潮娇喘视频 国产又色又爽又黄又刺激18 | 久久亚洲国产午夜精品理论片 | 亚洲综合一 | 久久这里只精品国产99热 | 麻豆久久婷婷国产综合五月 | 热久久国产欧美一区二区精品 | 天堂精品高清1区2区3区 | 午夜影院一区二区三区 |