Java插件式開發 動態加載Jar


背景

為了項目的擴展性,很多項目往往都會使用插件的方式為項目增加新功能,比如開發某種聊天機器人,增加擴展功能。這種方式非常靈活而且比較容易開發,本文就簡單探討一下Java如何動態加載Jar實現插件化開發。

規范或協議

在開始之前,首先需要定義一種規范,加載插件后如何調用插件內的方法,如何獲取插件的名稱版本號等信息。

如果有開發過安卓的Xposed插件應該知道,Xposed插件需要添加一個xposed_init文件,內容為入口類全名。

本文只是做個簡單的演示,具體實現方式可以不同

此處我們定義plugin.properties作為插件的入口,加載jar后,讀取mainClass的值作為入口類,版本號等信息可以自行添加,此處省略。

一般情況下,插件和項目都會依賴同一個庫,插件去實現庫中的接口或繼承抽象類,項目加載插件調用方法,不過此處就不做演示。

編寫插件

簡單編寫一個打印傳入內容的插件

入口類

package cn.montaro.plugins;

public class Test {
    public void print(String text) {
        System.out.println("我是插件我被調用了");
        System.out.println(text);
    }
}

plugin.properties文件

mainClass=cn.montaro.plugins.Test

image

打包成jar

編寫插件加載器

package cn.montaro.loader;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.util.Properties;

public class PluginLoader {

    private final static String PROPERTIES_NAME = "plugin.properties";
    private final static String MAIN_CLASS = "mainClass";

    /**
     * 加載jar文件
     *
     * @param jarFilePath jar文件路徑
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static Class loadJar(String jarFilePath) throws IOException, ClassNotFoundException {
        ClassLoader classLoader = getClassLoader(jarFilePath);
        Properties properties = getProperties(classLoader, PROPERTIES_NAME);
        String mainClass = properties.getProperty(MAIN_CLASS);
        return loadClass(classLoader, mainClass);
    }

    /**
     * 獲得ClassLoader
     *
     * @param jarFilePath jar文件路徑
     * @return
     * @throws MalformedURLException
     */
    private static final ClassLoader getClassLoader(String jarFilePath) throws MalformedURLException {
        File jarFile = new File(jarFilePath);
        if (!jarFile.exists()) {
            return null;
        }
        URL url = jarFile.toURI().toURL();
        URLClassLoader classLoader = new URLClassLoader(new URL[]{url}, null);
        return classLoader;
    }

    /**
     * 獲得jar中的properties
     *
     * @param classLoader    classLoader
     * @param propertiesName 文件名稱
     * @return
     * @throws IOException
     */
    private static Properties getProperties(ClassLoader classLoader, String propertiesName) throws IOException {
        InputStream propertiesStream = classLoader.getResourceAsStream(propertiesName);
        Properties properties = new Properties();
        properties.load(propertiesStream);
        return properties;
    }

    /**
     * 加載類
     *
     * @param classLoader classLoader
     * @param className   全類名
     * @return
     * @throws ClassNotFoundException
     */
    private static Class loadClass(ClassLoader classLoader, String className) throws ClassNotFoundException {
        Class<?> clazz = classLoader.loadClass(className);
        return clazz;
    }

}

加載插件

將插件打包成jar

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        String jarFilePath = "D:\\Projects\\plugin-test\\target\\plugin-test-1.0-SNAPSHOT.jar";
        Class mainClass = PluginLoader.loadJar(jarFilePath);
        Object o = mainClass.newInstance();
        Method print = mainClass.getDeclaredMethod("print", String.class);
        print.invoke(o, "23333");
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM