- 浏览: 74592 次
- 来自: ...
文章分类
最新评论
-
qingquan_11205:
[color=red][/color] [size=small ...
shell -
aimbin:
数据库并发操作存在的异常情况 觉得讲的不怎么清楚,推算着想不过 ...
【转】事务隔离级别 -
fandayrockworld:
哇,博主总结的太好了,厉害。
最近遇到一个Image加载图片过 ...
Flex内存泄露问题
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]-->RTMPMinaConnection
Red5如何启动?在它的启动过程中如何初始化这些关键类?
这里探讨的是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版的原因。
响应请求的流程如下:
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]-->RTMPMinaConnection
Red5如何启动?在它的启动过程中如何初始化这些关键类?
这里探讨的是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版的原因。
发表评论
-
记录nginx+tomcat+memcached+msm负载均衡,session共享
2013-03-06 18:33 4008环境centos5.5,jdk 1.7.0 ... -
[转]Maven常用命令
2011-09-23 16:11 859Maven常用命令: 1. 创建Maven的普通java项目: ... -
[转]java内存回收机制
2010-08-09 15:07 1202引言 Java的堆是一个运 ... -
【转】两阶段提交
2010-04-08 18:14 995两阶段提交协议 实现分布式事务的关键就是两阶段提交协议。在此 ... -
【转】事务隔离级别
2010-04-08 16:35 889事务的四个属性:原子性(atomicity)、一致性(cons ... -
rsync同步镜像配置
2009-03-12 12:25 2073转自:http://www.liyue.org/tec ... -
java.nio.Buffer缓冲区基础[转]
2009-01-06 14:22 7806缓冲区基础 抽象类Buffer是java.nio包支持缓冲区 ... -
Java:重写equals()和hashCode()
2008-11-28 17:26 10541.何时需要重写equals() 当一个类有自己特有的“逻辑相 ... -
再论Java Swing线程
2008-11-26 16:58 1892不正确的Swing线程是运 ... -
[转]细说Java GUI:AWT,SWT,Swing
2008-11-25 16:00 1550Overview概述 Java GU ... -
[转]Seam增强了JSF
2008-09-25 15:09 1538Seam采用的JSF作为表现层技术,但是标准的jsf有很多的不 ... -
[转]Developing Custom Converters
2008-04-28 17:36 10194.1) Introduction In most of t ... -
[转][opencms]在OpenCms中利用Java代码删除、创建、更新用户!
2008-01-11 17:51 1566<% org.opencms.file.Cms ... -
[转][opencms]移动文件的简单示例
2008-01-11 15:42 1113下面的简单示例实现了将目录/home01/中的多于8个的文件移 ... -
开始接触SEAM
2007-07-26 18:28 1100开始接触SEAM。记下一些东西: Each Seam com ...
相关推荐
通过分析和学习这个源代码,你可以了解到如何在实际项目中应用这些概念。 总的来说,初始化颜色对话框并自定义颜色集是C#中提升用户体验的一个实用技巧。通过设置`ColorDialog`的`CustomColors`属性,开发者可以为...
根据提供的文件信息,我们可以深入分析该聊天室项目的关键技术点及其实现原理。 ### 一、Red5服务器端应用实现 #### 1.1 应用基础结构 在Red5服务器中,应用程序通常通过继承`ApplicationAdapter`类来实现。在这个...
`lred.cc`通常包含了LRED算法的函数实现,包括初始化、更新状态、决定是否丢弃数据包等核心功能。而`lred.h`文件则定义了相关的结构体、变量和函数原型,供其他模块调用和实现。 在LRED的初始值设置中,可能涉及...
7. **boot.jar**: 这个JAR文件是Red5服务器启动时加载的第一个JAR,负责初始化服务器环境,加载配置,并启动核心服务。 8. **Makefile**: Makefile是一个用于自动化构建过程的文件,通常在Unix/Linux环境中使用。它...
"逆变器控制程序源代码详解" 逆变器控制程序源代码是采用C语言编写的控制程序,主要用于逆变器的控制。该程序通过对逆变器的控制实现更加准确的控制,且具有文字注释,易于理解。 首先,程序中引入了两个头文件`...
通过研究这些源代码,开发者可以深入理解如何将Red5与Android结合,构建完整的直播解决方案,包括如何初始化和配置Red5服务器,以及如何在Android应用中集成RTMP库进行直播和播放。 总的来说,构建一个Red5与...
### S3C2410的Bootloader (Vivi) 源代码分析 #### Vivi简介 Vivi是一款由韩国Mizi Research Inc.开发的Bootloader,它主要用于ARM9系列处理器,支持多种不同的硬件平台。Vivi具有两种主要的工作模式:启动加载模式...
- **代码编辑与调试**:该插件提供了对Red5项目的源代码编辑支持,包括自动补全、语法高亮、错误检查等功能,极大地提高了编码效率。同时,还集成了调试工具,允许开发者在Eclipse环境中直接对Red5应用进行断点调试...
- 项目模板:提供预设的Red5项目结构,简化项目初始化。 - 部署工具:方便地将项目部署到本地或远程的Red5服务器。 - 调试支持:设置断点,单步执行,查看变量值,帮助找出代码中的错误。 总的来说,Red5的Eclipse/...
- **文件描述**:本文件为一个简单的贪吃蛇游戏的C语言源代码,适用于初学者作为课程设计或学习参考。 - **标签**:贪吃蛇、源代码、C语言 ### 2. 代码结构与组织 #### 2.1 头文件包含 - **`#include<stdio.h>`**...
Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个...
核心线程 init()主要是来进行一些外设初始化的工作的,包括调用 do_basic_setup()完成外设及其驱动程序的加载和初始化。并完成文件系统初始化和 root 文件系统的安装。 8. mingetty 当 do_basic_setup()函数返回...
- 通过分析oflaDemo的源代码,开发者可以学习如何在自己的应用中集成Red5的功能。 总的来说,这个压缩文件包含了一个运行中的Red5服务器的`WEB-INF`目录,其中的`red5-web.properties`和`web.xml`是理解并配置Red5...
1. **下载Red5**:访问Red5官方网站或其他可信源下载Red5-1.0.0-with-oflaDemo压缩包。 2. **解压Red5**:将下载的压缩包解压到合适的位置。 3. **启动Red5**:在解压后的目录下,找到`red5.bat`(Windows环境下)或...
这些类提供了初始化方法,接受参数如中心点坐标、半径、宽度、高度等,以及颜色和填充样式等属性。例如,你可以这样创建一个红色的圆: ```python from graphics import * win = GraphWin("My Circle", 500, 500) ...
在这个文件中,我们可以预期会看到游戏的初始化、游戏规则、用户交互以及游戏循环等功能的实现。开发者可能使用了类(如`Jewel`类)来表示不同的宝石,并用矩阵或列表结构来存储游戏盘面的状态。矩阵的元素可能代表...
SQL文件包含创建表的语句以及初始化数据的插入操作。例如,用户表的创建可以通过以下SQL语句完成: ```sql CREATE TABLE `user_table` ( `user_id` int(32) NOT NULL AUTO_INCREMENT, `username` varchar(30) NOT ...