Java如何在運行時動態加載Jar

導讀:在實際項目開發中,有時會遇到需動態加載jar包的應用場景。如將Flink的UDF自定義方法制作成方法庫(既打成一個Jar),在提交給Flink集群的Job中動態加載jar便可使用。下面將舉一個簡單實現Java動態加載Jar的例子。

  • 環境準備
  • 動態加載Jar實現
  • 解析與拓展

環境準備

為了便於實現Demo,這裡構建一個模塊化Maven項目dynamicloading,項目包含:dyna-loading-function方法庫模塊、dyna-loading-core核心模塊。

Java如何在運行時動態加載Jar

在dyna-loading-function中編寫方法

編寫一個方法抽象類,及一個實現類Split,class

<code>/**
 * 方法抽象類
 */
public abstract class AbstractFunction {
    
    public abstract void eval(String s);
}


/**
*  字符串截取方法
*/
public class Split extends AbstractFunction {

    @Override
    public void eval(String s) {
        System.out.println("對字符串"+s+"進行截取操作");
    }
}
/<code>

將dyna-loading-function打成Jar包

Java如何在運行時動態加載Jar

在dyna-loading-core模塊實現動態加載Jar

<code>import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class dynaLoadTest {

    public static void main(String[] args) throws Exception{
        //jar所在路徑
        String jarPath = "C:\\repo\\com\\wxb\\dyna-loading-function\\1.0-SNAPSHOT\\dyna-loading-function-1.0-SNAPSHOT.jar";
        loadJar(jarPath);
        //利用反射
        Class> aClass = Class.forName("function.Split");
        Object instance = aClass.newInstance();
       //調用方法
        aClass.getDeclaredMethod("eval", String.class).invoke(instance,
                "hello word");
    }

    //動態加載Jar
    public static void loadJar(String jarPath) {
        File jarFile = new File(jarPath);
        //文件存在
        if (jarFile.exists() == false) {
            System.out.println("jar file not found.");
            return;
        }
        //從URLClassLoader類加載器中獲取類的addURL方法
        Method method = null;
        try {
            method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        } catch (NoSuchMethodException | SecurityException e1) {
            e1.printStackTrace();
        }
        // 獲取方法的訪問權限
        boolean accessible = method.isAccessible();
        try {
            //修改訪問權限為可寫
            if (accessible == false) {
                method.setAccessible(true);
            }
            // 獲取系統類加載器
            URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            //獲取jar文件的url路徑
            URL url = jarFile.toURI().toURL();
            //jar路徑加入到系統url路徑裡
            method.invoke(classLoader, url);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            method.setAccessible(accessible);
        }
    }

}


/<code>

運行

Java如何在運行時動態加載Jar

解析與拓展

ClassLoader是類加載器,其具體作用就是將class文件加載到jvm虛擬機中去,程序就可以正確運行了。java程序運行的時候,類必須被加載到jvm虛擬機中才可以正常使用。但不是所有的class文件都在啟動的時候全部加載,根據資料java最早就是為嵌入式系統而設計的,內存寶貴。如果開始時就把所有類都加載到jvm中,有些class可能在整個運行過程中都不會被用到,這樣便會佔用寶貴的內存。因此啟動時會先把保證程序運行的基礎類一次性加載到jvm中,其它class等到jvm用到的時候再通過動態加載將其加載到jvm虛擬中。

Java如何在運行時動態加載Jar

Java中內置了很多的類加載器,而ClassLoader是所有類加載器的基類,它是個抽象類,其定義了類加載最核心的操作。因本文主題是動態加載Jar,所以下面我們主要討論URLClassLoader。

Java如何在運行時動態加載Jar

URLClassLoader

URLClassLoader繼承自SecureClassLoader,支持從jar文件和文件夾中獲取class。而SecureClassLoader繼承於ClassLoader。

核心代碼:

<code>//1、通過getDeclaredMethod獲取URLClassLoader的addURL,這一步的目的是為了設置addURL方法可寫
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);

//2、獲取 URLClassLoader加載器
 URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();

//3、獲取目標jar的URL
URL url = jarFile.toURI().toURL();

//4、執行addURL方法,通過URLclassLoader從指定jar中獲取class並動態加到jvm虛擬機裡
 method.invoke(classLoader, url);

//5、class成功被動態加載進虛擬機後,就可以利用反射獲取
Class> aClass = Class.forName("function.Split");/<code>

最後

感謝您的閱讀,如果喜歡本文歡迎關注和轉發,本頭條號將堅持原創,持續分享IT技術知識。對於文章內容有其他想法或意見建議等,歡迎提出共同討論共同進步


分享到:


相關文章: