0%

java插件化设计开发

问题

java实现动态从jar包加载插件并运行.

实现

  • 定义插件运行的接口,用户需要自己实现的
public interface PluginService {
    /**
     * 插件运行方法
     */
    void process();
}
  • 定义插件实体类
@Data
public class Plugin {
    /**
     * 插件名称
     */
    private String pluginName;
    /**
     * jar包完整路径
     */
    private String jarPath;
    /**
     * class完整路径
     */
    private String className;
}
  • 定义插件异常
public class PluginException extends Exception {

    public PluginException(String message) {
        super(message);
    }
}
  • 定义插件管理类
@Data
@NoArgsConstructor
public class PluginManager {

    private Map<String, Class> clazzMap = new HashMap<>();

    public PluginManager(List<Plugin> plugins) throws PluginException {
        initPlugins(plugins);
    }

    public void initPlugin(Plugin plugin) throws PluginException {
        try {
//            URL url = new URL("file:" + plugin.getJarPath());
            URL url = new File(plugin.getJarPath()).toURI().toURL();
            URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
            Class clazz = classLoader.loadClass(plugin.getClassName());
            clazzMap.put(plugin.getClassName(), clazz);
        } catch (Exception e) {
            throw new PluginException("plugin " + plugin.getPluginName() + " init error," + e.getMessage());
        }
    }

    public void initPlugins(List<Plugin> plugins) throws PluginException {
        for (Plugin plugin : plugins) {
            initPlugin(plugin);
        }
    }

    public PluginService getInstance(String className) throws PluginException {
        Class clazz = clazzMap.get(className);
        Object instance = null;
        try {
            instance = clazz.newInstance();
        } catch (Exception e) {
            throw new PluginException("plugin " + className + " instantiate error," + e.getMessage());
        }
        return (PluginService) instance;
    }
}
  • 定义插件配置文件
<!-- 采用xml方式存储配置,dom4j解析 -->
<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.1</version>
</dependency>
public class PluginXmlParser {

    public static List<Plugin> getPluginList() throws PluginException {

        List<Plugin> list = new ArrayList<>();

        SAXReader saxReader = new SAXReader();
        Document document = null;
        try {
            document = saxReader.read(new File("plugin.xml"));
        } catch (Exception e) {
            throw new PluginException("read plugin.xml error," + e.getMessage());
        }
        Element root = document.getRootElement();
        List<?> plugins = root.elements("plugin");
        for (Object pluginObj : plugins) {
            Element pluginEle = (Element) pluginObj;
            Plugin plugin = new Plugin();
            plugin.setPluginName(pluginEle.elementText("name"));
            plugin.setJarPath(pluginEle.elementText("jar"));
            plugin.setClassName(pluginEle.elementText("class"));
            list.add(plugin);
        }
        return list;
    }
}
  • 运行测试类
public class Main {
    public static void main(String[] args) throws PluginException {
        // 从配置文件加载插件
        List<Plugin> pluginList = PluginXmlParser.getPluginList();
        PluginManager pluginManager = new PluginManager(pluginList);

        for (Plugin plugin : pluginList) {
            PluginService pluginService = pluginManager.getInstance(plugin.getClassName());
            System.out.println("开始执行[" + plugin.getPluginName() + "]插件...");
            // 调用插件
            pluginService.process();
            System.out.println("[" + plugin.getPluginName() + "]插件执行完成");
        }

        // 动态加载插件
        Plugin plugin = new Plugin();
        plugin.setPluginName("B插件");
        plugin.setJarPath("D:\\flinkDemo\\java8\\out\\artifacts\\test\\test.jar");
        plugin.setClassName("com.deri.stream.plugina.PluginB");
        pluginManager.initPlugin(plugin);
        PluginService pluginService = pluginManager.getInstance("com.deri.stream.plugina.PluginB");
        pluginService.process();
    }
}
  • 插件A/B/C
public class PluginA implements PluginService {
    @Override
    public void process() {
        System.out.println("Plugin A.");
    }
}
public class PluginB implements PluginService {
    @Override
    public void process() {
        System.out.println("Plugin B.");
    }
}
public class PluginC implements PluginService {
    @Override
    public void process() {
        System.out.println("Plugin C.");
    }
}
  • 插件配置文件
<?xml version="1.0" encoding="UTF-8"?>
<plugins>
    <plugin>
        <name>A插件</name>
        <jar>D:\flinkDemo\java8\out\artifacts\test\test.jar</jar>
        <class>com.deri.stream.plugina.PluginA</class>
    </plugin>
</plugins>

参考链接