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

How Tomcat Works(十一)

系統 1809 0

本文接下來分析tomcat的類載入器,tomcat需要實現一個自定義的載入器,而不能使用系統類載入器

(1)限制serlvet訪問當前運行的java虛擬機中環境變量CLASSPATH指明的路徑下的所有類和庫,而只允許載入WEB-INF/class目錄及其子目錄下的類,和從部署的庫到WEB-INF/lib目錄載入類

(2)提供自動重載的功能,即當WEB-INF/class目錄或WEB-INF/lib目錄下的類發生變化時,Web應用程序會重新載入這些類

我們先來回顧一下java的類載入器,當我們創建java類的實例時,都必須先將類載入到內存中,java虛擬機使用類載入器來載入需要的類

JVM使用三種類型的類載入器來載入所需要的類,分別為引導類載入器(bootstrap class loader)、擴展類載入器(extensions class loader)和系統類載入器(system class loader)

  • 引導類加載器(bootstrap class loader):它用來加載 Java 的核心庫,是用原生代碼來實現的,并不繼承自 java.lang.ClassLoader。
  • 擴展類加載器(extensions class loader):它用來加載 Java 的擴展庫。Java 虛擬機的實現會提供一個擴展庫目錄。該類加載器在此目錄里面查找并加載 Java 類。
  • 系統類加載器(system class loader):它根據 Java 應用的類路徑(CLASSPATH)來加載 Java 類。一般來說,Java 應用的類都是由它來完成加載的。可以通過 ClassLoader.getSystemClassLoader()來獲取它。

JVM采用一種代理模型的類載入機制,可以解決類載入過程中的安全性問題;每當系統需要載入一個類的時候,會首先調用系統類載入器,而系統類載入器將載入類的任務委派給其父載入器,即擴展類載入器,同樣擴展類載入器將載入類的任務委派給其父載入器,即引導類載入器;因此引導類載入器會首先執行載入某個類的任務,如果引導類載入器找不到需要載入的類,那么擴展類載入器嘗試載入該類,如果擴展類載入器也找不到該類,就輪到系統類載入器繼續執行載入任務。如果系統類載入器還是找不到該類,則會拋出java.lang.ClassNotFoundException異常

Tomcat中的載入器是指Web應用程序載入器,而不僅僅指類載入器,載入器必須實現org.apache.catalina.Loader接口

      
        public
      
      
        interface
      
      
         Loader {

      
      
        public
      
      
         ClassLoader getClassLoader();

      
      
        public
      
      
         Container getContainer();

      
      
        public
      
      
        void
      
      
         setContainer(Container container);

      
      
        public
      
      
         DefaultContext getDefaultContext();

      
      
        public
      
      
        void
      
      
         setDefaultContext(DefaultContext defaultContext);    

      
      
        public
      
      
        boolean
      
      
         getDelegate();

      
      
        public
      
      
        void
      
       setDelegate(
      
        boolean
      
      
         delegate);

      
      
        public
      
      
         String getInfo();

      
      
        public
      
      
        boolean
      
      
         getReloadable();

      
      
        public
      
      
        void
      
       setReloadable(
      
        boolean
      
      
         reloadable);

      
      
        public
      
      
        void
      
      
         addPropertyChangeListener(PropertyChangeListener listener);

      
      
        public
      
      
        void
      
      
         addRepository(String repository);

      
      
        public
      
      
         String[] findRepositories();

      
      
        public
      
      
        boolean
      
      
         modified();

      
      
        public
      
      
        void
      
      
         removePropertyChangeListener(PropertyChangeListener listener);
}
      
    

下面我們來具體來分析tomcat容器中 Web應用程序載入器的具體實現,即org.apache.catalina.loader.WebappLoader類實現了上面的Loader接口,負責載入Web應用程序中所使用到的類。

WebappLoader類會創建org.apache.catalina.loader.WebappClassLoader類的實例作為其類載入器;

同時WebappLoader類也實現了org.apache.catalina.Lifecycle接口,可以由其相關聯的容器來啟動或關閉;

此外,WebappLoader類還實現了java.lang.Runnable接口,通過一個線程不斷地調用其類載入器的modified()方法。如果modified()方法返回true, WebappLoader的實例會通知其關聯的servlet容器(在這里是Context類的實例),然后由Context實例來完成類的重新載入。

當調用WebappLoader類的start()方法時,會完成以下幾項重要工作:

(1)創建一個類載入器

(2)設置倉庫

(3)設置類路徑

(4)設置訪問權限

(5)啟動一個新線程來支持自動重載

WebappLoader類會調用其私有方法createClassLoader()方法來創建默認的類載入器

      
        /**
      
      
        
     * Create associated classLoader.
     
      
      
        */
      
      
        private
      
      
         WebappClassLoader createClassLoader()
        
      
      
        throws
      
      
         Exception {

        Class clazz 
      
      =
      
         Class.forName(loaderClass);
        WebappClassLoader classLoader 
      
      = 
      
        null
      
      
        ;

        
      
      
        if
      
       (parentClassLoader == 
      
        null
      
      
        ) {
            
      
      
        //
      
      
         Will cause a ClassCast is the class does not extend WCL, but
            
      
      
        //
      
      
         this is on purpose (the exception will be caught and rethrown)
      
      
            classLoader =
      
         (WebappClassLoader) clazz.newInstance();
        } 
      
      
        else
      
      
         {
            Class[] argTypes 
      
      = { ClassLoader.
      
        class
      
      
         };
            Object[] args 
      
      =
      
         { parentClassLoader };
            Constructor constr 
      
      =
      
         clazz.getConstructor(argTypes);
            classLoader 
      
      =
      
         (WebappClassLoader) constr.newInstance(args);
        }

        
      
      
        return
      
      
         classLoader;

    }
      
    

String loaderClass 的默認值為org.apache.catalina.loader.WebappClassLoader

啟動方法后面的設置倉庫、設置類路徑、設置訪問權限等都與類載入器的初始化相關

WebappLoader類支持自動重載功能,如果WEB-INF/class目錄或WEB-INF/lib目錄下的某些類被重新編譯了,那么這些類會自動重新載入,而無需重啟tomcat。WebappLoader類使用一個線程周期性地檢查每個資源的時間戳,我們可以調用setCheckInterval()方法設置間隔時間

      
        /**
      
      
        
     * The background thread that checks for session timeouts and shutdown.
     
      
      
        */
      
      
        public
      
      
        void
      
      
         run() {

        
      
      
        if
      
       (debug >= 1
      
        )
            log(
      
      "BACKGROUND THREAD Starting"
      
        );

        
      
      
        //
      
      
         Loop until the termination semaphore is set
      
      
        while
      
       (!
      
        threadDone) {

            
      
      
        //
      
      
         Wait for our check interval
      
      
                    threadSleep();

            
      
      
        if
      
       (!
      
        started)
                
      
      
        break
      
      
        ;

            
      
      
        try
      
      
         {
                
      
      
        //
      
      
         Perform our modification check
      
      
        if
      
       (!
      
        classLoader.modified())
                    
      
      
        continue
      
      
        ;
            } 
      
      
        catch
      
      
         (Exception e) {
                log(sm.getString(
      
      "webappLoader.failModifiedCheck"
      
        ), e);
                
      
      
        continue
      
      
        ;
            }

            
      
      
        //
      
      
         Handle a need for reloading
      
      
                    notifyContext();
            
      
      
        break
      
      
        ;

        }

        
      
      
        if
      
       (debug >= 1
      
        )
            log(
      
      "BACKGROUND THREAD Stopping"
      
        );

    }
      
    

在上面run()方法里面的循環中,首先使線程休眠一段時間,然后調用 WebappLoader實例的類載入器的 modified()方法檢查已經載入的類是否被修改,肉沒有修改則重新執行循環;否則調用私有方法notifyContext(),通知與WebappLoader實例相關聯的Context容器重新載入相關類

      
        /**
      
      
        
     * Notify our Context that a reload is appropriate.
     
      
      
        */
      
      
        private
      
      
        void
      
      
         notifyContext() {

        WebappContextNotifier notifier 
      
      = 
      
        new
      
      
         WebappContextNotifier();
        (
      
      
        new
      
      
         Thread(notifier)).start();

    }
      
    

上面方法中的WebappContextNotifier為內部類,實現了Runnable接口

      
        /**
      
      
        
     * Private thread class to notify our associated Context that we have
     * recognized the need for a reload.
     
      
      
        */
      
      
        protected
      
      
        class
      
       WebappContextNotifier 
      
        implements
      
      
         Runnable {

        
      
      
        /**
      
      
        
         * Perform the requested notification.
         
      
      
        */
      
      
        public
      
      
        void
      
      
         run() {
            ((Context) container).reload();
        }
    }
      
    

下面我們來分析web應用程序中負責載入類的類載入器org.apache.catalina.loader.WebappClassLoader,該類繼承自java.net.URLClassLoader,同時實現了org.apache.catalina.loader.Reloader接口

      
        public
      
      
        interface
      
      
         Reloader {
   
      
      
        public
      
      
        void
      
      
         addRepository(String repository);

      
      
        public
      
      
         String[] findRepositories();
   
      
      
        public
      
      
        boolean
      
      
         modified();

}
      
    

該接口用來與倉庫操作相關,同時檢查web應用程序中的某個servlet或相關的類是否被修改

每個由WebappClassLoader載入的類,都視為資源,由org.apache.catalina.loader.ResourceEntry類的實例表示,存儲了類的相關信息

      
        public
      
      
        class
      
      
         ResourceEntry {
  
      
      
        public
      
      
        long
      
       lastModified = -1
      
        ;
   
      
      
        public
      
      
        byte
      
      [] binaryContent = 
      
        null
      
      
        ;
   
      
      
        public
      
       Class loadedClass = 
      
        null
      
      
        ;

      
      
        public
      
       URL source = 
      
        null
      
      
        ;

      
      
        public
      
       URL codeBase = 
      
        null
      
      
        ;

      
      
        public
      
       Manifest manifest = 
      
        null
      
      
        ;

      
      
        public
      
       Certificate[] certificates = 
      
        null
      
      
        ;

}
      
    

在WebappClassLoader類中,所有已經緩存的類存儲在名為resourceEntries的HashMap類型的變量中,而載入失敗的類被存儲在另一個名為notFoundResources的HashMap類型的變量中

下面是WebappClassLoader的loadClass()方法的具體實現

      
        public
      
       Class loadClass(String name, 
      
        boolean
      
      
         resolve)
        
      
      
        throws
      
      
         ClassNotFoundException {
        
      
      
        if
      
       (debug >= 2
      
        )
            log(
      
      "loadClass(" + name + ", " + resolve + ")"
      
        );
        Class clazz 
      
      = 
      
        null
      
      
        ;

        
      
      
        //
      
      
         Don't load classes if class loader is stopped
      
      
        if
      
       (!
      
        started) {
            log(
      
      "Lifecycle error : CL stopped"
      
        );
            
      
      
        throw
      
      
        new
      
      
         ClassNotFoundException(name);
        }

        
      
      
        //
      
      
         (0) Check our previously loaded local class cache
      
      
        clazz =
      
         findLoadedClass0(name);
        
      
      
        if
      
       (clazz != 
      
        null
      
      
        ) {
            
      
      
        if
      
       (debug >= 3
      
        )
                log(
      
      "  Returning class from cache"
      
        );
            
      
      
        if
      
      
         (resolve)
                resolveClass(clazz);
            
      
      
        return
      
      
         (clazz);
        }

        
      
      
        //
      
      
         (0.1) Check our previously loaded class cache
      
      
        clazz =
      
         findLoadedClass(name);
        
      
      
        if
      
       (clazz != 
      
        null
      
      
        ) {
            
      
      
        if
      
       (debug >= 3
      
        )
                log(
      
      "  Returning class from cache"
      
        );
            
      
      
        if
      
      
         (resolve)
                resolveClass(clazz);
            
      
      
        return
      
      
         (clazz);
        }

        
      
      
        //
      
      
         (0.2) Try loading the class with the system class loader, to prevent
        
      
      
        //
      
      
               the webapp from overriding J2SE classes
      
      
        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;
                    System.out.println(error);
                    se.printStackTrace();
                    log(error);
                    
      
      
        throw
      
      
        new
      
      
         ClassNotFoundException(error);
                }
            }
        }

        
      
      
        boolean
      
       delegateLoad = delegate ||
      
         filter(name);

        
      
      
        //
      
      
         (1) Delegate to our parent if requested
      
      
        if
      
      
         (delegateLoad) {
            
      
      
        if
      
       (debug >= 3
      
        )
                log(
      
      "  Delegating to parent classloader"
      
        );
            ClassLoader loader 
      
      =
      
         parent;
            
      
      
        if
      
       (loader == 
      
        null
      
      
        )
                loader 
      
      =
      
         system;
            
      
      
        try
      
      
         {
                clazz 
      
      =
      
         loader.loadClass(name);
                
      
      
        if
      
       (clazz != 
      
        null
      
      
        ) {
                    
      
      
        if
      
       (debug >= 3
      
        )
                        log(
      
      "  Loading class from parent"
      
        );
                    
      
      
        if
      
      
         (resolve)
                        resolveClass(clazz);
                    
      
      
        return
      
      
         (clazz);
                }
            } 
      
      
        catch
      
      
         (ClassNotFoundException e) {
                ;
            }
        }

        
      
      
        //
      
      
         (2) Search local repositories
      
      
        if
      
       (debug >= 3
      
        )
            log(
      
      "  Searching local repositories"
      
        );
        
      
      
        try
      
      
         {
            clazz 
      
      =
      
         findClass(name);
            
      
      
        if
      
       (clazz != 
      
        null
      
      
        ) {
                
      
      
        if
      
       (debug >= 3
      
        )
                    log(
      
      "  Loading class from local repository"
      
        );
                
      
      
        if
      
      
         (resolve)
                    resolveClass(clazz);
                
      
      
        return
      
      
         (clazz);
            }
        } 
      
      
        catch
      
      
         (ClassNotFoundException e) {
            ;
        }

        
      
      
        //
      
      
         (3) Delegate to parent unconditionally
      
      
        if
      
       (!
      
        delegateLoad) {
            
      
      
        if
      
       (debug >= 3
      
        )
                log(
      
      "  Delegating to parent classloader"
      
        );
            ClassLoader loader 
      
      =
      
         parent;
            
      
      
        if
      
       (loader == 
      
        null
      
      
        )
                loader 
      
      =
      
         system;
            
      
      
        try
      
      
         {
                clazz 
      
      =
      
         loader.loadClass(name);
                
      
      
        if
      
       (clazz != 
      
        null
      
      
        ) {
                    
      
      
        if
      
       (debug >= 3
      
        )
                        log(
      
      "  Loading class from parent"
      
        );
                    
      
      
        if
      
      
         (resolve)
                        resolveClass(clazz);
                    
      
      
        return
      
      
         (clazz);
                }
            } 
      
      
        catch
      
      
         (ClassNotFoundException e) {
                ;
            }
        }

        
      
      
        //
      
      
         This class was not found
      
      
        throw
      
      
        new
      
      
         ClassNotFoundException(name);

    }
      
    

在WebappClassLoader實例載入類時,首先是檢查緩存,然后再載入指定類(如果設置了安全管理。在代理載入器載入前還要檢測類型的安全)

---------------------------------------------------------------------------?

本系列How Tomcat Works系本人原創?

轉載請注明出處 博客園 刺猬的溫馴?

本人郵箱: ? chenying998179 # 163.com ( #改為@

本文鏈接 http://www.cnblogs.com/chenying99/p/3237389.html

How Tomcat Works(十一)


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 日本高清中文字幕在线观穿线视频 | 亚洲国产成人久久综合一 | 97精品一区二区三区在线不卡 | 久久久久久久国产精品毛片 | 日本免费一区视频 | 精品久久久中文字幕 | 国产精品亚洲精品观看不卡 | 青青国产成人精品视频 | 国产性色视频在线高清 | 青青国产在线播放 | 成人毛片大全 | 开心激情四房 | 日本tv欧美tv天堂 | 亚洲伊人久久大香线蕉啊 | 久久视频在线观看免费 | 国产一区二区三区成人久久片 | 不卡视频在线播放 | 91高清在线成人免费观看 | 日韩欧美国产成人 | 日本特黄在线观看免费 | 起碰成人免费公开网视频 | 片在线观看 | a毛片视频免费观看影院 | 九九视频免费在线 | 网曝门精品国产事件在线观看 | 狠狠色狠狠色综合久久第一次 | 久久久人体 | 国内精品久久久久久麻豆 | 国产精品美女久久久久网站 | 久草青青在线视频 | 青娱乐久久| 中文字幕一级毛片 | 国产在线精品福利91香蕉 | 免费观看欧美精品成人毛片能看的 | 狠狠操狠狠操狠狠操 | 久久久久久久一线毛片 | 嘿咻成人免费视频欧美激情 | 日本a视频在线 | 精品久久天干天天天按摩 | 激情久久免费视频 | 七次郎在线成人精品 |