java~通過ClassLoader動態加載~tomcat模型

在進行非WEB項目(Springboot)進行開發時,使用classLoader進行動態加載jar,並使用接口進行強類型轉換是沒有問題的,它們使用JVM下的URLClassLoader進行實現,而在基於tomcat的容器裏使用它時,出現了類型無法找到的問題,原因如下:

tomcat有個叫webApp的加載器它是先加載WEB-INF/classes後在加載WEB-INF/lib,但它的父加載器是它的common加載器,comon的父加載器是system加載器(和JVM的應用程序加載器功能差不多,不過指定了其他tomcat目錄下的加載,大家可以看看官網上的英文文檔),但是源碼中這個加載器是URLClassLoader的子類,而URLClassLoader默認父加載tomcat下是它的system加載器這麼設計和tomcat的配置有關,默認爲無爲false,會直接委託給tomcat的system加載器加載system委託最頂層的Bootstrap加載器(差不多是JVM裏起始加載器和擴展加載器的合併),但不管怎麼樣,項目在tomcat下自定義的或者URLClassLoader加載默認父加載器都不會是tomcat的webApp加載器而是system加載器,或者自定義的加載器或URLClassLoader和tomcat的webApp加載器沒有上下關係,所以動態創建類時設計到其他類時肯定會報CNF異常。

參考

https://blog.csdn.net/chenleixing/article/details/50042795
https://blog.csdn.net/chenleixing/article/details/47121661
http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html

Tomcat ClassLoader

1

解決方法

一 解決思路就是先獲取當前類的Class,然後獲取當前類的加載器,在自定義的加載器或者URLClassLoader加載器創建時指定爲它們的父加載器,這樣問題就會遊刃而解了,可能平常我們測試寫個簡單的例子沒遇到這個問題,因爲我們那時的URLClassLoader或者自定義的加載器的父加載器都是JVM的第三次加載器即應用程序加載,它是專門加載classpath下邊的或者指定的類或者jar的,依照雙親委託模型,肯定會找到引入路徑的那個類或者jar的。

二 使用Class.forName()的方式來動態加載指定的類,就不會存在這個問題,因爲這種方式一方面是能初始化類的靜態東西,再就是重要一點,就是採用的加載當前所在類的加載器來加載你指定的類,這樣你在tomcat下那就是它的webApp加載器啊,肯定不再出現這個問題,可能直接就從緩存裏找到了。

動態加載代碼

             URL url = new URL(packageUrl);
            // IDEA調試時與java運行時的ClassLoader是不同的,所以需要使用當前環境下的ClassLoader
            ClassLoader loader = new URLClassLoader(new URL[]{url}, clazz.getClassLoader()) {
                @Override
                public Class<?> loadClass(String name) throws ClassNotFoundException {
                    try {
                        String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                        InputStream is = getClass().getResourceAsStream(fileName);
                        if (is == null) {
                            return super.loadClass(name);
                        }
                        byte[] b = new byte[is.available()];
                        is.read(b);
                        return defineClass(name, b, 0, b.length);

                    } catch (IOException e) {
                        e.printStackTrace();
                        throw new ClassNotFoundException(name);
                    }
                }
            };
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章