您的位置:首页 > 其它

黑盒变白盒 - 调试 Red5 项目时查看 Red5 容器内部运行机制

2012-06-25 18:32 459 查看
如何使用 Red5 插件创建 Red5 项目?》介绍了如何在 Eclipse 下创建并调试 Red5 项目。有同学问,“我想在调试 Red5 应用程序时,能够边看Red5 API 边看到 Red5 容器内部运行情况。最好是能修改一下 Red5 源代码,然后看其运行情况。能做到吗?”
可以。本文从 Bootstrap 说起,介绍如何让 Red5 源代码“动起来”。
作者的 Red5 版本:0.9.1 Final;Eclipse 版本:3.5.0(eclipse-jee-indigo-win32 版)。
得先把源码搞进 Eclipse。
Eclipse 装有 svn 插件的用户可以直接从官网检出:
http://red5.googlecode.com/svn/java/server/,tags 里选择 Red5 版本,作者选择的是 0_9_1,点 Finish 按钮。服务器在国外,耐心等待检出即可。
Eclipse 没有安装 svn 插件的用户可以先下载再导入:
打开 Red5 主页,选择 Logo 右侧的 Downloads -> Red5 Server,选择一个 Red5 版本的链接点进去,作者选择的是 0.9.1 Final,在打开的新页面中点击该版本的 ZIP 开始下载(当然你也可以选择 Source 文件直接下载源代码,但源码依赖的第三方 jar 包还需要去单独下载一下)。下载得到的 red5-0.9.1.zip 文件,将其解压缩。打开 Eclipse,选择 File->Import...->General->Existing Projects into Workspace,Select root directory 选择刚才解压缩得到的 red5-0.9.1,勾选 Copy projects into workspace,Finish,在 工作台有 red5_server 项目生成。然后在 Eclipse 工作台下的 red5_server 目录下解压缩 src.zip,并新建 test 目录。回到 Eclipse 刷新 red5_server 项目,会有很多 Errors,Java Build Path->Libraries->Add JARs... 勾选 lib 中所有的 jar 包,Errors 就没了。
作者采用的是后一种。OK,现在我们可以看到并调试 Red5 源代码了。
看了一下,仅其 Java 文件就有 2.5MB。偌大一项目,从哪里开始呢?
了解一个语言,从 HelloWorld 开始;了解一个程序,从 main 函数开始。
查看 Red5 安装目录下的 red5.bat,有如下几句:
if NOT DEFINED RED5_MAINCLASS set RED5_MAINCLASS=org.red5.server.Bootstrap
:launchRed5
echo Starting Red5
"%J***A_HOME%\bin\java" %JYTHON_OPTS% %J***A_OPTS% -cp "%RED5_CLASSPATH%" %RED5_MAINCLASS% %RED5_OPTS%

可见 Red5 的启动走的是 org.red5.server.Bootstrap。那我们就从 Bootstrap 看起吧。
自 R3379 版本之后,Red5 使用 org.red5.server.Bootstrap 作为程序入口类。这意味着 org.red5.server.Standalone 被废弃。
org.red5.server.Bootstrap 并没有出现在 Red5 官方 API 中,我们在 red5.jar 中是找不到它的,它被单独压缩到了 boot.jar 中,用于 Red5 的启动。
Bootstrap 的 main 函数的有效代码只有三句:
/**
	 * BootStrapping entry point
	 * 
	 * @param args command line arguments
	 * @throws Exception if error occurs
	 */
	public static void main(String[] args) throws Exception {
		//retrieve path elements from system properties
		String root = getRed5Root();		
		getConfigurationRoot(root);
		
		//bootstrap dependencies and start red5
		bootStrap();
			
		System.out.println("Bootstrap complete");
	}

我们逐一查看。先看第一句所调用的 getRed5Root 函数:
/**
	 * Gets the Red5 root
	 * 
	 * @return
	 * @throws IOException
	 */
	private static String getRed5Root() throws IOException {
		// look for red5 root first as a system property
		String root = System.getProperty("red5.root");
		// if root is null check environmental
		if (root == null) {
			//check for env variable
			root = System.getenv("RED5_HOME");
		}		
		// if root is null find out current directory and use it as root
		if (root == null || ".".equals(root)) {
			root = System.getProperty("user.dir");
			//System.out.printf("Current directory: %s\n", root);
		}
		//if were on a windows based os flip the slashes
		if (File.separatorChar != '/') {
			root = root.replaceAll("\\\\", "/");
		}
		//drop last slash if exists
		if (root.charAt(root.length()-1) == '/') {
			root = root.substring(0, root.length() - 1);
		}	
		//set/reset property
		System.setProperty("red5.root", root);
		
		System.out.printf("Red5 root: %s\n", root);
		return root;
	}

这是要找到 Red5 的根目录。源码注释的很详细,不再赘述。跑完这些语句后,作者的 Eclipse 控制台打印结果如下:
Red5 root: D:/javaprojects/red5_server
再看 getConfigurationRoot 方法:
/**
	 * Gets the configuration root
	 * 
	 * @param root
	 * @return
	 */
	private static String getConfigurationRoot(String root) {
		// look for config dir
		String conf = System.getProperty("red5.config_root");

		// if root is not null and conf is null then default it
		if (root != null && conf == null) {
			conf = root + "/conf";
		}

		//flip slashes only if windows based os
		if (File.separatorChar != '/') {
			conf = conf.replaceAll("\\\\", "/");
		}
		
		//set conf sysprop
		System.setProperty("red5.config_root", conf);
		System.out.printf("Configuation root: %s\n", conf);
		return conf;
	}

这个是在找 Red5 配置文件的目录。源码注释的很详细,不再赘述。跑完这些语句后,作者的 Eclipse 控制台打印结果如下:
Configuation root: D:/javaprojects/red5_server/conf
最后来看 bootStrap 句,这个调用的是 bootstrap 方法。这个方法的前半部分写的是启动前的一些属性设置,注释的很详细,不再赘述。直接从后半部分看起,后半部分源码如下:

//get current loader
		ClassLoader baseLoader = Thread.currentThread().getContextClassLoader();
		
		// build a ClassLoader
		ClassLoader loader = ClassLoaderBuilder.build();

		//set new loader as the loader for this thread
		Thread.currentThread().setContextClassLoader(loader);
		
		// create a new instance of this class using new classloader
		Object boot = Class.forName("org.red5.server.Launcher", true, loader).newInstance();
	
		Method m1 = boot.getClass().getMethod("launch", (Class[]) null);
		m1.invoke(boot, (Object[]) null);

		//not that it matters, but set it back to the original loader
		Thread.currentThread().setContextClassLoader(baseLoader);
这段代码的意思是,先把当前线程的 ClassLoader 置换成 ClassLoaderBuilder 自定义的 ClassLoader,后者的主要作用是将 Red5 依赖的第三方类库加载。之后使用反射机制动态调用 org.red5.server.Launcher.launch 方法。最后将当前线程的 ClassLoader 还原为置换前的 ClassLoader。就这些。
值得一提的是 org.red5.server.Launcher.launch 方法。这个方法要做的主要事情就是将 FileSystemXmlApplicationContext 初始化。熟悉 Spring 的朋友一定不会对这个类感到陌生,在这里它负责根据 red5.xml 中的配置将 Red5 容器初始化。
OK,现在可以把《如何使用 Red5 插件创建 Red5 项目?》中的 Red5 安装目录设置成 Eclipse 工作台下的 red5_server 目录了(新建 Red5 项目时调整步骤 4 和步骤 8 相关配置即可),调试 Red5 项目时,也可以对 Red5 的源代码进行断点跟踪,黑箱操作变白箱操作,快哉!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐