加载自定义插件

来源:互联网 发布:淘宝网店退押金 编辑:程序博客网 时间:2024/06/09 20:36

/** * 插件定义信息接口,包括以下信息:<br/> * <b>插件名称</b><br/> * <b>插件路径</b><br/> * <b>插件类型</b><br/> * <b>插件提供商</b><br/> * <b>插件激活器</b><br/> * <b>插件依赖的父插件定义集</b><br/> * <b>插件所有属性信息</b><br/> */public interface IPluginDefinition extends Serializable{    /**     * 获取插件的唯一名称     * @return 插件的唯一名称     */    public String getName();    /**     * 获取插件的URL路径     * @return 插件的URL路径     */    public URL getPath();    /**     * 获取插件的提供商     * @return 插件的提供商     */    public String getProvider();    /**     * 获取插件的激活器     * @return 插件的激活器     */    public String getActivator();    /**     * 获取插件的类路径     * @return 插件类路径     */    public IPluginClassPath getClassPath();    /**     * 获取插件配置文件中的所有属性信息     * @return 插件配置文件中的所有属性信息     */    public Attributes getConfig();}


public interface IPluginModule {/** * 加载插件 * @param pluginPath */public void load(File pluginPath);/** * 卸载当前插件 */public void unload();/** * 插件目录 * @return */public File getPluginPath();/** * 标识是否已经加载过 * @return */public boolean isLoaded();/** * 获取插件激活器 */public IPluginActivator getPluginActivator();/** * 获取该插件的ClassLoader * @return */public ClassLoader getPluginLoader();/** * 获取插件的名字 * @return */    public String getPluginName();        /**     * 获取该插件的监控节点配置以及服务     * @return     */    public IPluginDefinition getPluginDefinition();}



/** * 插件配置解析,生成PluginDefinition对象 */public class PluginResolver {private static final String PROTOCOL_FILE = "file";private static final String JAR = ".jar";private static final String LIB = "lib";private static final String CLASS_PATH = "classpath";private static final String AGENT_PLUGIN_XML = "datacenter-plugin.xml";public static PluginResolver INSTANCE = new PluginResolver();private Map<String, IPluginResolver> resolvers = new HashMap<String, IPluginResolver>(4);static {        INSTANCE.resolvers.put(PROTOCOL_FILE, new FolderPathResolver());    }static interface IPluginResolver {        PluginDefinition resolvePlugin(XMLBuilder builder, URL url) throws Exception;    }public PluginDefinition resolvePlugin(URL url) throws PluginResolveException {        String protocol = url.getProtocol();IPluginResolver resolver = resolvers.get(protocol);if (resolver == null) {throw new PluginResolveException(String.format("Unsupport protocol [%s]", protocol));}try {Document document = DocumentDescriptor.INSTANCE.loadPluginXML(url);return resolver.resolvePlugin(XMLBuilder.createBuilder(document), url);} catch (Exception e) {throw new PluginResolveException("resolve config error!", e);}    }private static class FolderPathResolver implements IPluginResolver {public PluginDefinition resolvePlugin(XMLBuilder builder, URL url) throws Exception {String pluginName     = loadPluginName(builder);String provider       = loadPluginProvider(builder);String activator      = loadPluginActivator(builder);Attributes attributes = loadAttribtes(builder.findNode("/plugin/attributes"));Assert.isNotNull(pluginName, "plugin Name must be not null");Assert.isNotNull(activator, "activator must be not null");IPluginClassPath classpath  = new PluginClassPath(url, attributes.getString(CLASS_PATH));return new PluginDefinition(pluginName, url, activator, provider, classpath , attributes);}private String loadPluginName(XMLBuilder builder) throws Exception {String pluginName = XMLBuilder.getAttribute(builder.findNode("/plugin"), "name");if(pluginName != null) {return pluginName.trim();}return null;}private String loadPluginProvider(XMLBuilder builder) throws Exception {String provider = XMLBuilder.getAttribute(builder.findNode("/plugin"), "provider");if(provider != null) {return provider.trim();}return null;}private String loadPluginActivator(XMLBuilder builder) throws Exception {String activator = XMLBuilder.getAttribute(builder.findNode("/plugin//controller"), "class");if(activator != null) {return activator.trim();}return null;}private static Attributes loadAttribtes(Node parent) throws Exception {Attributes attributes = new Attributes();NodeList attributeNodes = parent.getChildNodes();for (int i = 0; i < attributeNodes.getLength(); i++) {Node node = attributeNodes.item(i);if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("attribute")) {// get attributesString name   = XMLBuilder.getAttribute(node, "name");String value  = XMLBuilder.getAttribute(node, "value");attributes.put(name, value);}}return attributes;}}}



/** * 插件类路径信息定义实现类,包含对路径的解析和处理,包含目录和jar包两种 * 形式。 * * 目录形式: *   1. 该目录当作classpath *   2. 该目录直接子层的jar包也纳入classpath * * jar包形式: *   1. 直接将jar包的URL纳入classpath *    * 默认打入插件下面的lib包 */public class PluginClassPath implements IPluginClassPath {private static final String JAR = ".jar";private static final String LIB = "lib";private List<URL> pathURL = new ArrayList<URL>();    PluginClassPath(URL pluginPath, String path) throws PluginResolveException {    resolve(pluginPath); //解析默认    resolve(pluginPath, path);    }        @SuppressWarnings("deprecation")protected void resolve(URL pluginPath) throws PluginResolveException {    File libPath = new File(pluginPath.getFile(), LIB);if (libPath.exists()) {File[] files = libPath.listFiles(new FileFilter() {public boolean accept(File file) {if (file.getName().endsWith(JAR)) {return true;}return false;}});for (File file : files) {try {pathURL.add(file.toURL());} catch (MalformedURLException e) {throw new PluginResolveException(e);}}}    }    /**     * 解析类路径URL地址,首先基于“,”进行路径分割,分为两种类别处理:目录和jar包。     *     * 目录形式:     *   1. 该目录当作classpath     *   2. 该目录直接子层的jar包也纳入classpath     *     * jar包形式:     *   1. 直接将jar包的URL纳入classpath     *     * @param pluginDir 插件路径     * @param path classpath相对路径,以“,”分割     * @throws PluginResolveException 解析错误时抛出该异常     */    protected void resolve(URL pluginDir, String path) throws PluginResolveException{        if(StringUtil.isNullOrEmpty(path)) {            //do nothing        } else {            String[] array = path.split(",");            List<URL> list = new ArrayList<URL>(array.length);            for(String p : array) {                if(StringUtil.isNullOrEmpty(p)) {                    continue;                }                p = p.trim();                try {                    URL pathURL = null;                    File f = new File(pluginDir.getFile(), p);                    if(f.exists()) {                        if(f.isFile() && f.getName().endsWith(".jar")) {                            pathURL = new URL(                                pluginDir.getProtocol(), pluginDir.getHost(),                                pluginDir.getPort(), pluginDir.getFile() + p);                        } else {                            pathURL = new URL(                                pluginDir.getProtocol(), pluginDir.getHost(),                                pluginDir.getPort(), pluginDir.getFile() + p + "/");                            File[] jars = f.listFiles(new FilenameFilter() {                                public boolean accept(File dir, String name) {                                    return name.endsWith(".jar");                                }                            });                            if(jars != null) {                                for(File jar : jars) {                                    list.add(FileUtil.getFileURL( jar ));                                }                            }                        }                        list.add(pathURL);                    } else {                        throw new PluginResolveException("Can not find classpath in directory " + f.getAbsolutePath());                    }                } catch (MalformedURLException e) {                   throw new PluginResolveException(e);                }            }            pathURL.addAll(list);            //file:/F:/XX/datacenter/lib/gson-1.7.1.jar, file:/F:/xx/datacenter/lib/joe.jar, file:/F:/xxx/datacenter/lib/spring.jar, file:/F:/xxx/datacenter/bin/]        }    }public URL[] getPath() {return pathURL.toArray(new URL[0]);}}

public class PluginManager {protected Logger logger = LoggerManager.getLogger(getClass());    public static final String PLUGIN_LISTS_XML = "plugin-lists.xml";    private static final String XML_PLUGIN = "/plugins//plugin";        private File pluginsPath = new File(DataCenterConfig.getHome(), "plugins");    private Map<String, IPluginModule> plugins = new ConcurrentHashMap<String, IPluginModule>();        private static final List<IPluginActuator> startActuators = new LinkedList<IPluginActuator>();private static final List<IPluginActuator> stopActuators  = new LinkedList<IPluginActuator>();static {        // 1. 创建执行器实例        ExtensionActuator extension = new ExtensionActuator();        ActivateActuator activate   = new ActivateActuator();                // 2. 注册启动执行器        startActuators.add(extension);        startActuators.add(activate);                // 3. 注册关闭执行器        stopActuators.add(activate);        stopActuators.add(extension);    }        /**     * 初始化的时候安装所有的插件,插件可以被卸载     */    public void init() throws Exception {    installPlugins(new File(pluginsPath, PLUGIN_LISTS_XML));    }        public void start() throws Exception{    for (IPluginModule plugin : plugins.values()) {            startPlugin(plugin);        }    }        private void startPlugin(IPluginModule plugin) {IPluginActivator activator = plugin.getPluginActivator();if (activator == null) {return;}int state = activator.getState();if (state == IPluginActivator.RUNNING || state == IPluginActivator.STARTING) { // 只要插件的状态不是RESOLVER,return; // 则不能启动该插件,因为该插件可能正在停止或者正在启动过程中或者已经启动}try {for (IPluginActuator actuator : startActuators) {actuator.start(plugin);}} catch (RuntimeException e) {logger.log(Level.SEVERE, "Initialize plugin actuator fail", e);throw e;}}        private void stopPlugin(IPluginModule plugin) {        logger.info("stoping plugin:" + plugin.getPluginName());        IPluginActivator activator = plugin.getPluginActivator();if (activator == null) {return;}int state = activator.getState();if (state == IPluginActivator.STOPPED || state == IPluginActivator.STOPPING) { // 只要插件的状态不是RESOLVER,return; // 则不能启动该插件,因为该插件可能正在停止或者正在启动过程中或者已经启动}try {for (IPluginActuator actuator : stopActuators) {actuator.stop(plugin);}} catch (RuntimeException e) {logger.log(Level.SEVERE, "stop plugin actuator fail", e);throw e;}        logger.info("stoped plugin:" + plugin.getPluginName());    }        public void reloadPlugin(String pluginName) throws Exception {    IPluginModule plugin = plugins.get(pluginName);    if(plugin != null) {    reloadPlugin(plugin);    }    }        private void reloadPlugin(IPluginModule plugin) throws Exception {    String pluginName = plugin.getPluginName();logger.info("reload plugin " + pluginName);if (plugins.get(pluginName) != null) {unInstallPluin(pluginName);startPlugin(loadPlugin(plugin.getPluginPath()));}    }        public void destory() throws Exception {    for (IPluginModule plugin : getPlugins()) {            stopPlugin(plugin);            plugin.unload();        }        plugins.clear();    }        public void installPlugin(String folder) throws Exception {        IPluginModule plugin = loadPlugin(folder, null);if (plugin != null) {plugins.put(plugin.getPluginName(), plugin);PluginContext.addPluginModule(plugin);}    }        public void unInstallPluin(String pluginName) throws Exception {    IPluginModule plugin = plugins.get(pluginName);    //先停止插件,然后卸载插件    stopPlugin(plugin);    if(plugin != null) {    plugin.unload();    }    plugins.remove(pluginName);    }    private void installPlugins(File path) throws Exception {        XMLBuilder builder = XMLBuilder.createBuilder(path);        NodeList pluginNodes = builder.findNodeList(XML_PLUGIN);        for (int i = 0; i < pluginNodes.getLength(); i++) {            Node node = pluginNodes.item(i);            if (node.getNodeType() == Node.ELEMENT_NODE) {                String folder   = XMLBuilder.getAttribute(node, "folder");                String enable   = XMLBuilder.getAttribute(node, "enable");                String filePath = XMLBuilder.getAttribute(node, "path");                if (Boolean.valueOf(enable)) {                    IPluginModule plugin = loadPlugin(folder, filePath);                    if(plugin != null) {                    plugins.put(plugin.getPluginName(), plugin);                        PluginContext.addPluginModule(plugin);                    }                }            }        }    }    private IPluginModule loadPlugin(String folder, String filePath) {if(StringUtil.isNullOrEmpty(filePath)) {File pluginFolder = new File(pluginsPath, folder);return loadPlugin(pluginFolder);} else {File pluginFolder = new File(filePath, folder);return loadPlugin(pluginFolder);}}        private IPluginModule loadPlugin(File pluginFolder) {    logger.info("start load plugin:" + pluginFolder.getName());    if (pluginFolder.exists() && pluginFolder.isDirectory()) {IPluginModule plugin = new PluginModule();plugin.load(pluginFolder);logger.info("plugin loaded:" + pluginFolder.getName());return plugin;} else {logger.severe("plugin folder error:" + pluginFolder.getName());return null;}    }    public Collection<IPluginModule> getPlugins() {        return Collections.unmodifiableCollection(plugins.values());    }    public File getPluginsPath() {        return pluginsPath;    }    public void setPluginsPath(File pluginsPath) {        this.pluginsPath = pluginsPath;    }}

public class PluginModule implements IPluginModule {private static Logger logger = LoggerManager.getLogger(PluginModule.class);private static final String JAR = ".jar";private static final String LIB = "lib";private static final String AGENT_PLUGIN_XML = "datacenter-plugin.xml";private IPluginActivator activator;private URLClassLoader pluginLoader;private String pluginName;private File pluginPath;private boolean isLoaded = false;private IPluginDefinition pluginDefinition;public void load(File pluginPath) {if (!isLoaded && pluginPath.isDirectory() && pluginPath.exists()) {this.pluginPath = pluginPath;loadPlugin(pluginPath);}}public void unload() {System.out.println(getPluginName() + ":stop");unloadNativeLibs(); //卸载本地代码}private void unloadNativeLibs() {        ClassLoader loader = getPluginLoader();        Field field;        try {            field = ClassLoader.class.getDeclaredField("nativeLibraries");            field.setAccessible(true);            Vector libs = (Vector) field.get(loader);            Iterator it = libs.iterator();            Object o;            while (it.hasNext()) {                o = it.next();                Method finalize = o.getClass().getDeclaredMethod("finalize", new Class[0]);                finalize.setAccessible(true);                finalize.invoke(o, new Object[0]);            }        } catch (Exception e) {            e.printStackTrace();        }    }@SuppressWarnings("deprecation")private void loadPlugin(File pluginPath) {try {pluginDefinition = PluginResolver.INSTANCE.resolvePlugin(pluginPath.toURL());if(pluginDefinition == null) {throw new PluginResolveException("resolve plugin config error!");}initClassLoader();//实例化插件启动器initPluginActivator();isLoaded = true;} catch (Exception e) {logger.log(Level.SEVERE, String.format("init plungin[%s] fail.", pluginPath.getPath()), e);}}private void initClassLoader() throws MalformedURLException {URL[] urls = pluginDefinition.getClassPath().getPath();  //[file:/F:/xx/demo/bin/]pluginLoader = new URLClassLoader(urls, ClassUtil.getClassLoader());}private void initPluginActivator() throws Exception {String cls = pluginDefinition.getActivator();Class clazz = pluginLoader.loadClass(cls);if (IPluginActivator.class.isAssignableFrom(clazz)) {activator  = (IPluginActivator)clazz.newInstance();}//throw new Exception(cls + " is not a subclass of:" + IPluginActivator.class);}public String getPluginName() {return pluginDefinition.getName();}public File getPluginPath() {return pluginPath;}public boolean isLoaded() {return isLoaded;}public ClassLoader getPluginLoader() {return pluginLoader;}public IPluginActivator getPluginActivator() {return activator;}public IPluginDefinition getPluginDefinition() {return pluginDefinition;}}


原创粉丝点击