Red5源代码分析如何响应rmpt的请求 – 关键类及其初始化过程【转载】

Red5如何响应rmpt的请求,中间涉及哪些关键类?响应请求的流程如下:

1.Red5在启动时会调用RTMPMinaTransport的start()方法,该方法会开启rmtp的socket监听端口(默认是1935),然后使用mina(apache的io操作类库)的api将RTMPMinaIoHandler绑定到该端口。

2.RTMPMinaIoHandler上定义了messageReceived、messageSent、sessionOpened和 sessionClosed等方法,当有socket请求时,相应的方法会被调用,这时RTMPMinaIoHandler会使用当前的socket连接 来创建一个RTMPMinaConnection(或者使用一个之前创建好的RTMPMinaConnection),并将其作为参数传递给定义于 RTMPHandler类上的相应的messageReceived、messageSent、connectionOpened和 connectionClosed方法。

3.RTMPHandler会调用Server类的lookupGlobal获得当前的GlobalScope,然后再利用GlobalScope 找到当前socket请求应该使用的WebScope(这个WebScope就是我们在自己的项目的WEB-INF\red5-web.xml中定义的 啦)。最后,RTMPHandler会调用RTMPMinaConnection的connect方法连接到相应的WebScope。

4.至此,控制流进入了我们自己项目中了,通常来说,WebScope又会将请求转移给ApplicationAdapter,由它来最终响应请求,而我们的项目通过重载ApplicationAdapter的方法来实现自己的逻辑。

简单的流程图:
Java代码

RTMPMinaIoHandler

|–[delegate method call and pass RTMPMinaConnection to]–>RTMPHandler

|–[call lookupGlobal method]–>Server

|–[use globalScope to lookup webScope]–>GlobalScope

|–[call connect method and pass WebScope to]–>RTMPMinaConnection

RTMPMinaIoHandler |--[delegate method call and pass RTMPMinaConnection to]-->RTMPHandler |--[call lookupGlobal method]-->Server |--[use globalScope to lookup webScope]-->GlobalScope |--[call connect method and pass WebScope to]-->RTMPMinaConnectionRed5如何启动?在它的启动过程中如何初始化这些关键类?

这里探讨的是Red5 standalone的启动过程(也就是我们执行red5.bat),关于Red5如何在tomcat中启动,目前仍在研究中。

Red5启动过程如下:

1.编辑red5.bat,找到关键的一行:

Java代码

C:\Program Files\Java\jre1.5.0_15\bin\java”

-Djava.security.manager

-Djava.security.policy=conf/red5.policy

-cp red5.jar;conf;bin org.red5.server.Standalone

C:\Program Files\Java\jre1.5.0_15\bin\java" -Djava.security.manager -Djava.security.policy=conf/red5.policy -cp red5.jar;conf;bin org.red5.server.Standalone

可以看到它是调用org.red5.server.Standalone作为程序启动的入口,这也是为什么使用eclipse在debug模式下 启动Standalone就可以调试Red5代码。需要注意的是,如果你要调试Red5,记得除了源代码(src)之外,把conf和webapps两个 文件夹都拷入项目中,并把conf加入classpath。
2.观察Standalone的main方法,你会看到它使用spring的 ContextSingletonBeanFactoryLocator来载入classpath下面的red5.xml,注意 ContextSingletonBeanFactoryLocator还会在下面的步骤中被使用,由于它是singleton的,所以保证了我们自己的 项目中定义的bean可以引用red5.xml中定义的bean,这个下面会有介绍。

Java代码

try {

ContextSingletonBeanFactoryLocator.getInstance(red5Config).useBeanFactory(“red5.common”);

} catch (Exception e) {

// Don’t raise wrapped exceptions as their stacktraces may confuse people…

raiseOriginalException(e);

}

try { ContextSingletonBeanFactoryLocator.getInstance(red5Config).useBeanFactory("red5.common"); } catch (Exception e) { // Don't raise wrapped exceptions as their stacktraces may confuse people... raiseOriginalException(e); }

3.查看red5.xml,这个文件首先定义了指向classpath:/red5-common.xml的名字为“red5.common”的 BeanFactory,注意它会是整个BeanFactory层次中的根节点,所以在red5-common.xml中定义的bean可以被其他地方所 引用。

Xml代码

<bean id=”red5.common” class=”org.springframework.context.support.FileSystemXmlApplicationContext”>

<constructor-arg><list><value>classpath:/red5-common.xml</value></list></constructor-arg>

</bean>

<bean id="red5.common"> <constructor-arg><list><value>classpath:/red5-common.xml</value></list></constructor-arg> </bean>

这里我们主要留意red5-common.xml中定义的类型为org.red5.server.Server的“red5.server”,它会在接下来很多地方被用到。

Xml代码

<bean id=”red5.server” class=”org.red5.server.Server”/>

<bean id="red5.server"/>

4.回到red5.xml,接着定义指向classpath:/red5-core.xml的名字为“red5.core”的BeanFactory,注意“red5.core”是以“red5.common”为parent context。

Xml代码

<bean id=”red5.core” class=”org.springframework.context.support.FileSystemXmlApplicationContext”>

<constructor-arg><list><value>classpath:/red5-core.xml</value></list></constructor-arg>

<constructor-arg><ref bean=”red5.common” /></constructor-arg>

</bean>

<bean id="red5.core"> <constructor-arg><list><value>classpath:/red5-core.xml</value></list></constructor-arg> <constructor-arg><ref bean="red5.common" /></constructor-arg> </bean>

查看red5-core.xml,这个文件主要定义了之前说过的RTMPMinaTransport,RMTPMinaIoHandler和 RTMPHandler这些类的Bean。对于RTMPMinaTransport,注意init-method=”start”这段代码,这说明 RTMPMinaTransport的start方法会在该Bean初始化时调用,正如上面提到的,该方法会做开启1935端口,绑定 RTMPMinaIoHandler到该端口等等的操作。对于RTMPHandler,注意它的server属性通过“red5.server”引用了定 义在parent context(red5-common.xml)上面的Server,通过它RTMPHandler能够找到GlobalScope,进而找到 WebScope。

Xml代码

<!– RTMP Handler –>

<bean id=”rtmpHandler”

class=”org.red5.server.net.rtmp.RTMPHandler”>

<property name=”server” ref=”red5.server” />

<property name=”statusObjectService” ref=”statusObjectService” />

</bean>

 

<!– RTMP Mina IO Handler –>

<bean id=”rtmpMinaIoHandler”

class=”org.red5.server.net.rtmp.RTMPMinaIoHandler”>

<property name=”handler” ref=”rtmpHandler” />

<property name=”codecFactory” ref=”rtmpCodecFactory” />

<property name=”rtmpConnManager” ref=”rtmpMinaConnManager” />

</bean>

 

<!– RTMP Mina Transport –>

<bean id=”rtmpTransport” class=”org.red5.server.net.rtmp.RTMPMinaTransport” init-method=”start” destroy-method=”stop”>

<property name=”ioHandler” ref=”rtmpMinaIoHandler” />

<property name=”address” value=”${rtmp.host}” />

<property name=”port” value=”${rtmp.port}” />

<property name=”receiveBufferSize” value=”${rtmp.receive_buffer_size}” />

<property name=”sendBufferSize” value=”${rtmp.send_buffer_size}” />

<property name=”eventThreadsCore” value=”${rtmp.event_threads_core}” />

<property name=”eventThreadsMax” value=”${rtmp.event_threads_max}” />

<property name=”eventThreadsQueue” value=”${rtmp.event_threads_queue}” />

<property name=”eventThreadsKeepalive” value=”${rtmp.event_threads_keepalive}” />

<!– This is the interval at which the sessions are polled for stats. If mina monitoring is not  enabled, polling will not occur. –>

<property name=”jmxPollInterval” value=”1000″ />

<property name=”tcpNoDelay” value=”${rtmp.tcp_nodelay}” />

</bean>

<!-- RTMP Handler --> <bean id="rtmpHandler" class="org.red5.server.net.rtmp.RTMPHandler"> <property name="server" ref="red5.server" /> <property name="statusObjectService" ref="statusObjectService" /> </bean> <!-- RTMP Mina IO Handler --> <bean id="rtmpMinaIoHandler" class="org.red5.server.net.rtmp.RTMPMinaIoHandler"> <property name="handler" ref="rtmpHandler" /> <property name="codecFactory" ref="rtmpCodecFactory" /> <property name="rtmpConnManager" ref="rtmpMinaConnManager" /> </bean> <!-- RTMP Mina Transport --> <bean id="rtmpTransport" init-method="start" destroy-method="stop"> <property name="ioHandler" ref="rtmpMinaIoHandler" /> <property name="address" value="${rtmp.host}" /> <property name="port" value="${rtmp.port}" /> <property name="receiveBufferSize" value="${rtmp.receive_buffer_size}" /> <property name="sendBufferSize" value="${rtmp.send_buffer_size}" /> <property name="eventThreadsCore" value="${rtmp.event_threads_core}" /> <property name="eventThreadsMax" value="${rtmp.event_threads_max}" /> <property name="eventThreadsQueue" value="${rtmp.event_threads_queue}" /> <property name="eventThreadsKeepalive" value="${rtmp.event_threads_keepalive}" /> <!-- This is the interval at which the sessions are polled for stats. If mina monitoring is not enabled, polling will not occur. --> <property name="jmxPollInterval" value="1000" /> <property name="tcpNoDelay" value="${rtmp.tcp_nodelay}" /> </bean>

5.再次回到red5.xml,接下来定义类型为org.red5.server.ContextLoader的bean,并在初始化后调用它的init方法。

Xml代码

<bean id=”context.loader” class=”org.red5.server.ContextLoader”  init-method=”init”>

<property name=”parentContext” ref=”red5.common” />

<property name=”contextsConfig” value=”red5.globals” />

</bean>

<bean id="context.loader" init-method="init"> <property name="parentContext" ref="red5.common" /> <property name="contextsConfig" value="red5.globals" /> </bean>

查看该方法的源代码,可以看到它会读取在classPath下面的red5.globals文件,对于每一行初始化一个以 “red5.common”为parent context的BeanFactory,具体来说,现在red5.globals中只有一行 default.context=${red5.root}/webapps/red5-default.xml,那么会创建一个名字为 “default.context”的指向webapps/red5-default.xml的Bean Factory,它以“red5.common”为parent context。

Java代码

protected void loadContext(String name, String config) {

log.debug(“Load context - name: ” + name + ” config: ” + config);

ApplicationContext context = new FileSystemXmlApplicationContext(

new String[] { config }, parentContext);

contextMap.put(name, context);

// add the context to the parent, this will be red5.xml

ConfigurableBeanFactory factory = ((ConfigurableApplicationContext) applicationContext)

.getBeanFactory();

// Register context in parent bean factory

factory.registerSingleton(name, context);

}

protected void loadContext(String name, String config) { log.debug("Load context - name: " + name + " config: " + config); ApplicationContext context = new FileSystemXmlApplicationContext( new String[] { config }, parentContext); contextMap.put(name, context); // add the context to the parent, this will be red5.xml ConfigurableBeanFactory factory = ((ConfigurableApplicationContext) applicationContext) .getBeanFactory(); // Register context in parent bean factory factory.registerSingleton(name, context); }

查看red5-default.xml,发现它主要是定义了GlobalScope的bean,然后把它注册到“red5.server”上。

Xml代码

<bean id=”global.scope” class=”org.red5.server.GlobalScope” init-method=”register”>

<property name=”server” ref=”red5.server” />

<property name=”name” value=”default” />

<property name=”context” ref=”global.context” />

<property name=”handler” ref=”global.handler” />

<property name=”persistenceClass”>

<value>org.red5.server.persistence.FilePersistence</value>

</property>

</bean>

<bean id="global.scope" init-method="register"> <property name="server" ref="red5.server" /> <property name="name" value="default" /> <property name="context" ref="global.context" /> <property name="handler" ref="global.handler" /> <property name="persistenceClass"> <value>org.red5.server.persistence.FilePersistence</value> </property> </bean>

6.继续看red5.xml,最后定义类型为org.red5.server.jetty.JettyLoader的bean,并且在初始化后调用它的init方法,查看该方法源代码,很明显它是初始化并且启动jetty这个web server。

Xml代码

<bean id=”jetty6.server” class=”org.red5.server.jetty.JettyLoader” init-method=”init” autowire=”byType” depends-on=”context.loader”>

<property name=”webappFolder” value=”${red5.root}/webapps” />

</bean>

<bean id="jetty6.server" init-method="init" autowire="byType" depends-on="context.loader"> <property name="webappFolder" value="${red5.root}/webapps" /> </bean>

7.到了这里似乎所有的初始化和启动都完毕了,但是问题就来了,这里仅仅定义了 RTMPMinaIoHandler,RTMPHandler,Server和GlobalScope,但是在我们之前提到过的Red5响应rmpt的请 求的过程中,还需要有WebScope来最终处理RTMPMinaConnection,这个WebScope又是怎么配置并且加进来的呢?
8.查看webapps下的项目,这里以oflaDemo为例,查看WEB-INF下面的web.xml,发现有以下三个参数 contextConfigLocation,locatorFactorySelector和parentContextKey,同时还有一个 org.springframework.web.context.ContextLoaderListener。

Xml代码

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/red5-*.xml</param-value>

</context-param>

 

<context-param>

<param-name>locatorFactorySelector</param-name>

<param-value>red5.xml</param-value>

</context-param>

 

<context-param>

<param-name>parentContextKey</param-name>

<param-value>default.context</param-value>

</context-param>

 

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/red5-*.xml</param-value> </context-param> <context-param> <param-name>locatorFactorySelector</param-name> <param-value>red5.xml</param-value> </context-param> <context-param> <param-name>parentContextKey</param-name> <param-value>default.context</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>

查看这个listener的javadoc,其实这个listener会在web app(就是我们自己的项目)启动时,创建一个指向contextConfigLocation(其实就是WEB-INF\red5-web.xml)的 Bean Factory,同时为它设置parent context。这个parent context实际上是使用locatorFactorySelector找到ContextSingletonBeanFactoryLocator, 进而使用parentContextKey找到定义在这个locator里面的Bean Fanctory,由于ContextSingletonBeanFactoryLocator是singleton的,所以这个 ContextSingletonBeanFactoryLocator对象跟我们在第2步中拿到的对象是一样的,而由于 parentContextKey被设置成“default.context”,这就意味着该parent context是第5步中定义的名为“default.context”的Bean Factory。基于以上的参数,我们得到这样一个Bean Factory的链条,由上至下分别是

Java代码

conf\red5-common.xml -> webapps\red5-default.xml -> webapps\oflaDemo\WEB-INF\red5-web.xml

conf\red5-common.xml -> webapps\red5-default.xml -> webapps\oflaDemo\WEB-INF\red5-web.xml

这就使得red5-web.xml可以使用red5-common.xml和red5-default.xml中定义的bean。
9.最后查看webapps\oflaDemo\WEB-INF\red5-web.xml,它定义了类型为 org.red5.server.WebScope的bean,初始化了它的server(指向“red5.server”),parent(指向 “global.scope”)等属性,最后调用它的register方法初始化,查看该方法源代码,发现它会把自己注册到GlobalScope上面, 至此所有的关键类的初始化完毕。

Xml代码

<bean id=”web.scope” class=”org.red5.server.WebScope” init-method=”register”>

<property name=”server” ref=”red5.server” />

<property name=”parent” ref=”global.scope” />

<property name=”context” ref=”web.context” />

<property name=”handler” ref=”web.handler” />

<property name=”contextPath” value=”${webapp.contextPath}” />

<property name=”virtualHosts” value=”${webapp.virtualHosts}” />

</bean>

<bean id="web.scope" init-method="register"> <property name="server" ref="red5.server" /> <property name="parent" ref="global.scope" /> <property name="context" ref="web.context" /> <property name="handler" ref="web.handler" /> <property name="contextPath" value="${webapp.contextPath}" /> <property name="virtualHosts" value="${webapp.virtualHosts}" /> </bean>Spring beanFactory 的层次图
Java代码

conf\red5-common.xml

|– conf\red5-core.xml

|– webapps\red5-default.xml

|– webapps\root\WEB-INF\red5-web.xml

|– webapps\SOSample\WEB-INF\red5-web.xml

|– webapps\oflaDemo\WEB-INF\red5-web.xml

conf\red5-common.xml |-- conf\red5-core.xml |-- webapps\red5-default.xml |-- webapps\root\WEB-INF\red5-web.xml |-- webapps\SOSample\WEB-INF\red5-web.xml |-- webapps\oflaDemo\WEB-INF\red5-web.xml

看清了Red5 Standalone的启动过程,感觉为了实现自定义项目集成到Red5的核心服务上,Red5 Standalone非常依赖于spring的多个Bean Factory之间的复杂层次关系,之所以Red5能建立这样一种层次关系,是因为它能够控制jetty这样一个嵌入式的web server。问题在于,一旦Red5需要作为一个web app运行在类似Tomcat这样的独立的web server上面,那么整个过程就很不一样了,所以后很多东西都要改,我想这也是为什么Red5 0.8 RC1为什么只有安装版但还没有war版的原因。

最后,如果哪位成功在Tomcat上配置过Red5 0.7的war版本,还请告诉我一声,我试了0.6的war可以,不知道0.7为什么老不行。。。

Tags : | add comments 

25
Red5源码分析(转载 semi-sleep)Posted by k20101010@gmail.com on 星期二 一 25, 2011Under red5

Red5如何响应rmpt的请求,中间涉及哪些关键类?
响应请求的流程如下:

1.Red5在启动时会调用RTMPMinaTransport的start()方法,该方法会开启rmtp的socket监听端口(默认是1935),然后使用mina(apache的io操作类库)的api将RTMPMinaIoHandler绑定到该端口。

2.RTMPMinaIoHandler 上定义了messageReceived、messageSent、sessionOpened和 sessionClosed等方法,当有socket请求时,相应的方法会被调用,这时RTMPMinaIoHandler会使用当前的socket连接 来创建一个RTMPMinaConnection(或者使用一个之前创建好的RTMPMinaConnection),并将其作为参数传递给定义于 RTMPHandler类上的相应的messageReceived、messageSent、connectionOpened和 connectionClosed方法。

3.RTMPHandler会调用Server类的lookupGlobal获得当前的 GlobalScope,然后再利用GlobalScope 找到当前socket请求应该使用的WebScope(这个WebScope就是我们在自己的项目的WEB-INF\red5-web.xml中定义的 啦)。最后,RTMPHandler会调用RTMPMinaConnection的connect方法连接到相应的WebScope。

4.至此,控制流进入了我们自己项目中了,通常来说,WebScope又会将请求转移给ApplicationAdapter,由它来最终响应请求,而我们的项目通过重载ApplicationAdapter的方法来实现自己的逻辑。

简单的流程图:
Java代码

1. RTMPMinaIoHandler
2.   |–[delegate method call and pass RTMPMinaConnection to]–>RTMPHandler
3.      |–[call lookupGlobal method]–>Server
4.      |–[use globalScope to lookup webScope]–>GlobalScope
5.      |–[call connect method and pass WebScope to]–>RTMPMinaConnection

RTMPMinaIoHandler
|–[delegate method call and pass RTMPMinaConnection to]–>RTMPHandler
|–[call lookupGlobal method]–>Server
|–[use globalScope to lookup webScope]–>GlobalScope
|–[call connect method and pass WebScope to]–>RTMPMinaConnection

Red5如何启动?在它的启动过程中如何初始化这些关键类?

这里探讨的是Red5 standalone的启动过程(也就是我们执行red5.bat),关于Red5如何在tomcat中启动,目前仍在研究中。

Red5启动过程如下:

1.编辑red5.bat,找到关键的一行:
Java代码

1. C:\Program Files\Java\jre1.5.0_15\bin\java”
2.   -Djava.security.manager
3.   -Djava.security.policy=conf/red5.policy
4.   -cp red5.jar;conf;bin org.red5.server.Standalone

C:\Program Files\Java\jre1.5.0_15\bin\java”
-Djava.security.manager
-Djava.security.policy=conf/red5.policy
-cp red5.jar;conf;bin org.red5.server.Standalone

可 以看到它是调用org.red5.server.Standalone作为程序启动的入口,这也是为什么使用eclipse在debug模式下启动 Standalone就可以调试Red5代码。需要注意的是,如果你要调试Red5,记得除了源代码(src)之外,把conf和webapps两个文件 夹都拷入项目中,并把conf加入classpath。

2.观察Standalone的main方法,你会看到它使用 spring的 ContextSingletonBeanFactoryLocator来载入classpath下面的red5.xml,注意 ContextSingletonBeanFactoryLocator还会在下面的步骤中被使用,由于它是singleton的,所以保证了我们自己的 项目中定义的bean可以引用red5.xml中定义的bean,这个下面会有介绍。
Java代码

1. try {
2.     ContextSingletonBeanFactoryLocator.getInstance(red5Config).useBeanFactory(“red5.common”);
3. } catch (Exception e) {
4.     // Don’t raise wrapped exceptions as their stacktraces may confuse people…
5.     raiseOriginalException(e);
6. }

try {
ContextSingletonBeanFactoryLocator.getInstance(red5Config).useBeanFactory(“red5.common”);
} catch (Exception e) {
// Don’t raise wrapped exceptions as their stacktraces may confuse people…
raiseOriginalException(e);
}

3. 查看red5.xml,这个文件首先定义了指向classpath:/red5-common.xml的名字为“red5.common”的 BeanFactory,注意它会是整个BeanFactory层次中的根节点,所以在red5-common.xml中定义的bean可以被其他地方所 引用。
Xml代码

1. <bean id=”red5.common”>
2.     <constructor-arg><list><value>classpath:/red5-common.xml</value></list></constructor-arg>
3. </bean>

<bean id=”red5.common”>
<constructor-arg><list><value>classpath:/red5-common.xml</value></list></constructor-arg>
</bean>

这里我们主要留意red5-common.xml中定义的类型为org.red5.server.Server的“red5.server”,它会在接下来很多地方被用到。
Xml代码

1. <bean id=”red5.server”/>

<bean id=”red5.server”/>

4.回到red5.xml,接着定义指向classpath:/red5-core.xml的名字为“red5.core”的BeanFactory,注意“red5.core”是以“red5.common”为parent context。
Xml代码

1. <bean id=”red5.core”>
2.     <constructor-arg><list><value>classpath:/red5-core.xml</value></list></constructor-arg>
3.     <constructor-arg><ref bean=”red5.common” /></constructor-arg>
4. </bean>

<bean id=”red5.core”>
<constructor-arg><list><value>classpath:/red5-core.xml</value></list></constructor-arg>
<constructor-arg><ref bean=”red5.common” /></constructor-arg>
</bean>

查 看red5-core.xml,这个文件主要定义了之前说过的RTMPMinaTransport,RMTPMinaIoHandler和 RTMPHandler这些类的Bean。对于RTMPMinaTransport,注意init-method=”start”这段代码,这说明 RTMPMinaTransport的start方法会在该Bean初始化时调用,正如上面提到的,该方法会做开启1935端口,绑定 RTMPMinaIoHandler到该端口等等的操作。对于RTMPHandler,注意它的server属性通过“red5.server”引用了定 义在parent context(red5-common.xml)上面的Server,通过它RTMPHandler能够找到GlobalScope,进而找到 WebScope。
Xml代码

1. <!– RTMP Handler –>
2. <bean id=”rtmpHandler”
3.    >
4.     <property name=”server” ref=”red5.server” />
5.     <property name=”statusObjectService” ref=”statusObjectService” />
6. </bean>
7.
8. <!– RTMP Mina IO Handler –>
9. <bean id=”rtmpMinaIoHandler”
10.    >
11.     <property name=”handler” ref=”rtmpHandler” />
12.     <property name=”codecFactory” ref=”rtmpCodecFactory” />
13.     <property name=”rtmpConnManager” ref=”rtmpMinaConnManager” />
14. </bean>
15.
16. <!– RTMP Mina Transport –>
17. <bean id=”rtmpTransport” class=”org.red5.server.net.rtmp.RTMPMinaTransport” init-method=”start” destroy-method=”stop”>
18.     <property name=”ioHandler” ref=”rtmpMinaIoHandler” />
19.     <property name=”address” value=”${rtmp.host}” />
20.     <property name=”port” value=”${rtmp.port}” />
21.     <property name=”receiveBufferSize” value=”${rtmp.receive_buffer_size}” />
22.     <property name=”sendBufferSize” value=”${rtmp.send_buffer_size}” />
23.     <property name=”eventThreadsCore” value=”${rtmp.event_threads_core}” />
24.     <property name=”eventThreadsMax” value=”${rtmp.event_threads_max}” />
25.     <property name=”eventThreadsQueue” value=”${rtmp.event_threads_queue}” />
26.     <property name=”eventThreadsKeepalive” value=”${rtmp.event_threads_keepalive}” />
27.     <!– This is the interval at which the sessions are polled for stats. If mina monitoring is not  enabled, polling will not occur. –>
28.     <property name=”jmxPollInterval” value=”1000″ />
29.     <property name=”tcpNoDelay” value=”${rtmp.tcp_nodelay}” />
30. </bean>

<!– RTMP Handler –>
<bean id=”rtmpHandler”
class=”org.red5.server.net.rtmp.RTMPHandler”>
<property name=”server” ref=”red5.server” />
<property name=”statusObjectService” ref=”statusObjectService” />
</bean>

<!– RTMP Mina IO Handler –>
<bean id=”rtmpMinaIoHandler”
class=”org.red5.server.net.rtmp.RTMPMinaIoHandler”>
<property name=”handler” ref=”rtmpHandler” />
<property name=”codecFactory” ref=”rtmpCodecFactory” />
<property name=”rtmpConnManager” ref=”rtmpMinaConnManager” />
</bean>

<!– RTMP Mina Transport –>
<bean id=”rtmpTransport” init-method=”start” destroy-method=”stop”>
<property name=”ioHandler” ref=”rtmpMinaIoHandler” />
<property name=”address” value=”${rtmp.host}” />
<property name=”port” value=”${rtmp.port}” />
<property name=”receiveBufferSize” value=”${rtmp.receive_buffer_size}” />
<property name=”sendBufferSize” value=”${rtmp.send_buffer_size}” />
<property name=”eventThreadsCore” value=”${rtmp.event_threads_core}” />
<property name=”eventThreadsMax” value=”${rtmp.event_threads_max}” />
<property name=”eventThreadsQueue” value=”${rtmp.event_threads_queue}” />
<property name=”eventThreadsKeepalive” value=”${rtmp.event_threads_keepalive}” />
<!– This is the interval at which the sessions are polled for stats. If mina monitoring is not enabled, polling will not occur. –>
<property name=”jmxPollInterval” value=”1000″ />
<property name=”tcpNoDelay” value=”${rtmp.tcp_nodelay}” />
</bean>

5.再次回到red5.xml,接下来定义类型为org.red5.server.ContextLoader的bean,并在初始化后调用它的init方法。
Xml代码

1. <bean id=”context.loader”  init-method=”init”>
2.     <property name=”parentContext” ref=”red5.common” />
3.     <property name=”contextsConfig” value=”red5.globals” />
4. </bean>

<bean id=”context.loader” init-method=”init”>
<property name=”parentContext” ref=”red5.common” />
<property name=”contextsConfig” value=”red5.globals” />
</bean>

查 看该方法的源代码,可以看到它会读取在classPath下面的red5.globals文件,对于每一行初始化一个以 “red5.common”为parent context的BeanFactory,具体来说,现在red5.globals中只有一行 default.context=${red5.root}/webapps/red5-default.xml,那么会创建一个名字为 “default.context”的指向webapps/red5-default.xml的Bean Factory,它以“red5.common”为parent context。
Java代码

1. protected void loadContext(String name, String config) {
2.     log.debug(“Load context – name: ” + name + ” config: ” + config);
3.     ApplicationContext context = new FileSystemXmlApplicationContext(
4.             new String[] { config }, parentContext);
5.     contextMap.put(name, context);
6.     // add the context to the parent, this will be red5.xml
7.     ConfigurableBeanFactory factory = ((ConfigurableApplicationContext) applicationContext)
8.             .getBeanFactory();
9.     // Register context in parent bean factory
10.     factory.registerSingleton(name, context);
11. }

protected void loadContext(String name, String config) {
log.debug(“Load context – name: ” + name + ” config: ” + config);
ApplicationContext context = new FileSystemXmlApplicationContext(
new String[] { config }, parentContext);
contextMap.put(name, context);
// add the context to the parent, this will be red5.xml
ConfigurableBeanFactory factory = ((ConfigurableApplicationContext) applicationContext)
.getBeanFactory();
// Register context in parent bean factory
factory.registerSingleton(name, context);
}

查看red5-default.xml,发现它主要是定义了GlobalScope的bean,然后把它注册到“red5.server”上。
Xml代码

1. <bean id=”global.scope” init-method=”register”>
2.     <property name=”server” ref=”red5.server” />
3.     <property name=”name” value=”default” />
4.     <property name=”context” ref=”global.context” />
5.     <property name=”handler” ref=”global.handler” />
6.     <property name=”persistenceClass”>
7.         <value>org.red5.server.persistence.FilePersistence</value>
8.     </property>
9. </bean>

<bean id=”global.scope” init-method=”register”>
<property name=”server” ref=”red5.server” />
<property name=”name” value=”default” />
<property name=”context” ref=”global.context” />
<property name=”handler” ref=”global.handler” />
<property name=”persistenceClass”>
<value>org.red5.server.persistence.FilePersistence</value>
</property>
</bean>

6.继续看red5.xml,最后定义类型为org.red5.server.jetty.JettyLoader的bean,并且在初始化后调用它的init方法,查看该方法源代码,很明显它是初始化并且启动jetty这个web server。
Xml代码

1. <bean id=”jetty6.server” class=”org.red5.server.jetty.JettyLoader” init-method=”init” autowire=”byType” depends-on=”context.loader”>
2.     <property name=”webappFolder” value=”${red5.root}/webapps” />
3. </bean>

<bean id=”jetty6.server” init-method=”init” autowire=”byType” depends-on=”context.loader”>
<property name=”webappFolder” value=”${red5.root}/webapps” />
</bean>

7. 到了这里似乎所有的初始化和启动都完毕了,但是问题就来了,这里仅仅定义了 RTMPMinaIoHandler,RTMPHandler,Server和GlobalScope,但是在我们之前提到过的Red5响应rmpt的请 求的过程中,还需要有WebScope来最终处理RTMPMinaConnection,这个WebScope又是怎么配置并且加进来的呢?

8. 查看webapps下的项目,这里以oflaDemo为例,查看WEB-INF下面的web.xml,发现有以下三个参数 contextConfigLocation,locatorFactorySelector和parentContextKey,同时还有一个 org.springframework.web.context.ContextLoaderListener。
Xml代码

1. <context-param>
2.   <param-name>contextConfigLocation</param-name>
3.   <param-value>/WEB-INF/red5-*.xml</param-value>
4. </context-param>
5.
6. <context-param>
7.   <param-name>locatorFactorySelector</param-name>
8.   <param-value>red5.xml</param-value>
9. </context-param>
10.
11. <context-param>
12.   <param-name>parentContextKey</param-name>
13.   <param-value>default.context</param-value>
14. </context-param>
15.
16. <listener>
17.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
18. </listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/red5-*.xml</param-value>
</context-param>

<context-param>
<param-name>locatorFactorySelector</param-name>
<param-value>red5.xml</param-value>
</context-param>

<context-param>
<param-name>parentContextKey</param-name>
<param-value>default.context</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

查 看这个listener的javadoc,其实这个listener会在web app(就是我们自己的项目)启动时,创建一个指向contextConfigLocation(其实就是WEB-INF\red5-web.xml)的 Bean Factory,同时为它设置parent context。这个parent context实际上是使用locatorFactorySelector找到ContextSingletonBeanFactoryLocator, 进而使用parentContextKey找到定义在这个locator里面的Bean Fanctory,由于ContextSingletonBeanFactoryLocator是singleton的,所以这个 ContextSingletonBeanFactoryLocator对象跟我们在第2步中拿到的对象是一样的,而由于 parentContextKey被设置成“default.context”,这就意味着该parent context是第5步中定义的名为“default.context”的Bean Factory。基于以上的参数,我们得到这样一个Bean Factory的链条,由上至下分别是
Java代码

1. conf\red5-common.xml -> webapps\red5-default.xml -> webapps\oflaDemo\WEB-INF\red5-web.xml

conf\red5-common.xml -> webapps\red5-default.xml -> webapps\oflaDemo\WEB-INF\red5-web.xml

这就使得red5-web.xml可以使用red5-common.xml和red5-default.xml中定义的bean。

9. 最后查看webapps\oflaDemo\WEB-INF\red5-web.xml,它定义了类型为 org.red5.server.WebScope的bean,初始化了它的server(指向“red5.server”),parent(指向 “global.scope”)等属性,最后调用它的register方法初始化,查看该方法源代码,发现它会把自己注册到GlobalScope上面, 至此所有的关键类的初始化完毕。
Xml代码

1. <bean id=”web.scope” init-method=”register”>
2.     <property name=”server” ref=”red5.server” />
3.     <property name=”parent” ref=”global.scope” />
4.     <property name=”context” ref=”web.context” />
5.     <property name=”handler” ref=”web.handler” />
6.     <property name=”contextPath” value=”${webapp.contextPath}” />
7.     <property name=”virtualHosts” value=”${webapp.virtualHosts}” />
8. </bean>

<bean id=”web.scope” init-method=”register”>
<property name=”server” ref=”red5.server” />
<property name=”parent” ref=”global.scope” />
<property name=”context” ref=”web.context” />
<property name=”handler” ref=”web.handler” />
<property name=”contextPath” value=”${webapp.contextPath}” />
<property name=”virtualHosts” value=”${webapp.virtualHosts}” />
</bean>

Spring beanFactory 的层次图
Java代码

1. conf\red5-common.xml
2.   |– conf\red5-core.xml
3.   |– webapps\red5-default.xml
4.         |– webapps\root\WEB-INF\red5-web.xml
5.         |– webapps\SOSample\WEB-INF\red5-web.xml
6.         |– webapps\oflaDemo\WEB-INF\red5-web.xml

conf\red5-common.xml
|– conf\red5-core.xml
|– webapps\red5-default.xml
|– webapps\root\WEB-INF\red5-web.xml
|– webapps\SOSample\WEB-INF\red5-web.xml
|– webapps\oflaDemo\WEB-INF\red5-web.xml

Tags : | add comments 
25
RED5的API介紹-1Posted by k20101010@gmail.com on 星期二 一 25, 2011Under red5
org.red5.server.adapter.ApplicationAdapter 这一个类别是RED5中最基本也最重要的类别,是用在当flash用new NetConnetion,当执行connect()时,处理相关连线资料的类别。 在这个类别内,有几个比较值得
org.red5.server.adapter.ApplicationAdapter
这一个类别是RED5中最基本也最重要的类别,是用在当flash用new NetConnetion,当执行connect()时,处理相关连线资料的类别。
在这个类别内,有几个比较值得一提的函数,列举如下:
appConnect(IConnection conn, Object[] params)
当flash端执行NetConnection.connect(“rtmp://localhost/killerred5app”, “silver”);
server端会执行的基本连线动作都写在这边。
这个函数也是我们创子资料夹时,要去覆写的函数,来让伺服器能执行我们想要它去做的动作。
我们可以在red5-web.xml裡的id=web.handler的这个class设定执行此一路径的位置要呼叫的ApplicationAdapter继承函数来处理连线资料。
appJoin(IClient client, IScope app)/appLeave(IClient client, IScope app)
连接加入时触发的函数(以聊天室来说,就是在有人新进聊天室时会被呼叫)
appStart(IScope app)/appStop(IScope app)
appStart将在连接开始的时候自动触发,等同於FMS的onAppStart。 appStop则在关闭此连线时触发。
appConnect(IConnection conn, Object[] params) /appDisconnect(IConnection conn)
连线成功时和关闭连线时做的动作
connect(IConnection conn, IScope scope, Object[] params)
这是在连线时,会将连线结果丢回给client端的函式,例如连线成功或失败等。
addListener(IApplication listener)
加入一个监听器,当连线状态有任何改变时就会呼叫此函数。但开始连线并不会呼叫。
rejectClient() / rejectClient(Object reason)
这个函数可传值(一个物件)进入,也可不传值,主要在拒绝使用者的连线。
下面是官方说明文件对此一API的说明中译
ApplicationAdapter為Red5应用程序提供基础类,该类提供了操作SharedObjects 和 streams的方法,还有连接和服务列表。
ApplicationAdapter是一个应用程序基本的IScope,在你的应用程序种去控制流的操作,你可以实作 IStreamAwareScopeHandler接口,去实现你所想做的控制方法(例如: 控制主机负载量、负载量多少开始控管、多少时禁止存取等…)。
ApplicationAdapter提供给你一个有用的事件控制句,可以用於拦截流、授权用户等等。同时可以将所有的方法添加到子类中,可以 通过NetConnection.call方法在客户端调用。这与Flash Media Server不同,FMS需要将你的客户端方法保存在服务器端。Red5提供更加方便的方式进行远程方法调用。
官方的API说明文件可到此观看:
http://dl.fancycode.com/red5/api/index.html
posted @ 2012-07-05 22:30  点亮创想  阅读(497)  评论(0编辑  收藏  举报