Red5的共享对象有一条很关键:当没有客户端连这个共享对象时,该共享对象自动清空。客户端再次连接该共享对象时将创建新的同名共享对象,这时属性值为空。
创建:
当调用ApplicationAdapter的public boolean createSharedObject(IScope scope, String name, boolean persistent)方法时,就在scope下创建了一个名为name的共享对象。它又调用ISharedObjectService的createSharedObject方法。ISharedObjectService是在red5-common.xml中注入的,默认是org.red5.server.so.SharedObjectService。它的创建方法是:
1: /** {@inheritDoc} */2: public boolean createSharedObject(IScope scope, String name, boolean persistent) {3: if (hasSharedObject(scope, name)) {4: // The shared object already exists.5: return true;6: }
7: synchronized (scope) {8: final IBasicScope soScope = new SharedObjectScope(scope, name, persistent, getStore(scope, persistent));9: return scope.addChildScope(soScope);10: }
11: }
可以看到创建共享对象其实就是new了一个SharedObjectScope,它继承了BaseScope,实现了ISharedObject接口。
1: public class SharedObjectScope extends BasicScope implements ISharedObject, StatusCodes通过ApplicationAdapter的getSharedObject方法获取共享对象其实就是SharedObjectScope这个Scope!它有一个SharedObject成员,它负责存取具体的共享对象属性值。SharedObject并没有实现ISharedObject,我们平常操作的共享对象是ISharedObject(其实就是SharedObjectScope这个Scope),并非SharedObject对象。
当有客户端连接名为name的共享对象时,如果没有则调用ISharedObjectService的createSharedObject方法创建一个名为name的共享对象(scope)。
销毁:
客户端断开共享对象的连接,其实就是断开共享对象这个scope的连接!客户端发起断开共享对象的连接的事件时,RTMPHandler监听到SharedObject事件,进入onSharedObject处理函数。将共享对象消息分派给SharedObjectScope(实现ISharedObject接口)的dispatchEvent处理,根据消息的类型(SERVER_DISCONNECT)要么从rtmp连接中注销这个Scope(unregisterBasicScope),要么removeEventListener。
1: public void unregisterBasicScope(IBasicScope basicScope) {2: basicScopes.remove(basicScope);3: basicScope.removeEventListener(this);4: }它依然走了SharedObjectScope的removeEventListener方法。
1: @Override2: public void removeEventListener(IEventListener listener) {3: so.unregister(listener);4: //part 1 of the fix for TRAC #360 - if we have not been released by all that acquired then5: //keep on disconnection of the last listener6: if (so.isAcquired()) {7: keepOnDisconnect = true;8: }9: //remove the listener10: super.removeEventListener(listener);11: //part 2 of the fix for TRAC #360 - check acquire12: if (!so.isPersistentObject() && (so.getListeners() == null || so.getListeners().isEmpty()) && !so.isAcquired()) {13: getParent().removeChildScope(this);14: }15:
16: for (ISharedObjectListener soListener : serverListeners) {17: soListener.onSharedObjectDisconnect(this);18: }19: }so.unregister中
1: protected void unregister(IEventListener listener) {2: listeners.remove(listener);3: listenerStats.decrement();4: checkRelease();5: }调用了checkRelease()方法:
1: /**2: * Check if shared object must be released.3: */4: protected void checkRelease() {5: //part 3 of fix for TRAC #3606: if (!isPersistentObject() && listeners.isEmpty() && !isAcquired()) {7: log.info("Deleting shared object {} because all clients disconnected and it is no longer acquired.", name);8: if (storage != null) {9: if (!storage.remove(this)) {10: log.error("Could not remove shared object.");11: }12: }13: close();14: }15: }看到了吗“Deleting shared object {} because all clients disconnected and it is no longer acquired.”,。在close中删除了共享对象的所有属性。再回到removeEventListener中:
1: if (!so.isPersistentObject() && (so.getListeners() == null || so.getListeners().isEmpty()) && !so.isAcquired()) {2: getParent().removeChildScope(this);3: }这里将SharedObjectScope这个Scope删掉了。
客户端再次连到这个共享对象时,如果没有则再次创建:
1: if (!sharedObjectService.createSharedObject(scope, name, persistent)) {2: sendSOCreationFailed(conn, name, persistent);3: return;4: }
如果你的应用希望没有客户端连接时仍然保持着共享对象,可以通过checkRelease函数找解决办法——checkRelease有如下判断:
隐藏行号 复制代码 ? 这是一段程序代码。
if (!isPersistentObject() && listeners.isEmpty() && !isAcquired())只有当该共享对象不是持久化的且没有客户端监听且没有获取(acquireCount=0)时,才走close清空共享对象。所以要想满足不清空的需求,要么让其持久化,要么监听不为空,要么acquireCount>0。对于非持久化的共享对象。系统调用
隐藏行号 复制代码 ? 这是一段程序代码。
sharedObject.acquire();一下,就能保证所有客户端断开共享对象时acquireCount仍然大于0。以后需要释放的时候调用:
即可。隐藏行号 复制代码 ? 这是一段程序代码。
sharedObject.release();release函数源代码:
隐藏行号 复制代码 ? 这是一段程序代码。
public void release() {
if (acquireCount.get() == 0) { throw new RuntimeException("The shared object was not acquired before."); } if (acquireCount.decrementAndGet() == 0) {checkRelease();
}
}
当前acquireCount==0时调用release将会抛异常,提示“The shared object was not acquired before.”。