加载自定义插件

/**
 * 插件定义信息接口,包括以下信息:<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 attributes
					String 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;
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值