<1>
入口處從開始看
https://www.cnblogs.com/LQBlog/p/16594835.html#autoid-2-3-0
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#processMessage
private void processMessage(ServerMessage.Mutable[] messages, Context context, ServerMessageImpl message, Promise<Boolean> promise) { if (_logger.isDebugEnabled()) { _logger.debug("Processing {} on {}", message, this); } //爲message設置當前transport信息 message.setServerTransport(_transport); //爲message_bayeuxContext message.setBayeuxContext(_bayeuxContext); //爲session設置transport ServerSessionImpl session = context.session; if (session != null) { session.setServerTransport(_transport); } //獲得message channel String channel = message.getChannel(); //是否是握手請求 if (Channel.META_HANDSHAKE.equals(channel)) { if (messages.length > 1) { promise.fail(new IOException("protocol violation")); } else { if (session != null) { //設置爲null 握手之前不需要發送消息 session.setScheduler(null); } //處理握手請求 processMetaHandshake(context, message, promise); } } else { //握手之前主動推送消息 if (session != null && session.updateServerEndPoint(this)) { session.setScheduler(new WebSocketScheduler(context, message, 0)); } //是否是續約消息 if (Channel.META_CONNECT.equals(channel)) { processMetaConnect(context, message, Promise.from(proceed -> { if (proceed) { resume(context, message, Promise.from(y -> promise.succeed(true), promise::fail)); } else { promise.succeed(false); } }, promise::fail)); } else { //<2>普通消息 processMessage(context, message, promise); } } }
<2>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#processMessage
private void processMessage(Context context, ServerMessageImpl message, Promise<Boolean> promise) { ServerSessionImpl session = context.session; //<3>內部調用extends的incoming方法 _transport.getBayeux().handle(session, message, Promise.from(y -> _transport.processReply(session, message.getAssociated(), Promise.from(reply -> { if (reply != null) { context.replies.add(reply); } if (!isMetaConnectDeliveryOnly(session)) { context.sendQueue = true; } // Leave scheduleExpiration unchanged. promise.succeed(true); }, promise::fail)), promise::fail)); }
<3>
org.cometd.server.BayeuxServerImpl#handle
private void handle1(ServerSessionImpl session, ServerMessage.Mutable message, Promise<ServerMessage.Mutable> promise) { if (_logger.isDebugEnabled()) { _logger.debug("> {} {}", message, session); } ServerMessage.Mutable reply = message.getAssociated(); //session的有效性進行校驗 session斷開連接,或者 messageid與clientId對不上同時又不是握手請求 if (session == null || session.isDisconnected() || (!session.getId().equals(message.getClientId()) && !Channel.META_HANDSHAKE.equals(message.getChannel()))) { //消息追加錯誤 unknownSession(reply); promise.succeed(reply); } else { String channelName = message.getChannel(); //針對meta_connect session 執行續約 session.cancelExpiration(Channel.META_CONNECT.equals(channelName)); if (channelName == null) { error(reply, "400::channel_missing"); promise.succeed(reply); } else { //從服務器獲得channel ServerChannelImpl channel = getServerChannel(channelName); if (channel == null) { //channel沒有找到則先走創建channel流程 isCreationAuthorized(session, message, channelName, Promise.from(result -> { if (result instanceof Authorizer.Result.Denied) { String denyReason = ((Authorizer.Result.Denied)result).getReason(); error(reply, "403:" + denyReason + ":channel_create_denied"); promise.succeed(reply); } else { //<4>處理消息 handle2(session, message, (ServerChannelImpl)createChannelIfAbsent(channelName).getReference(), promise); } }, promise::fail)); } else { //<4>處理消息 handle2(session, message, channel, promise); } } } }
<4>
org.cometd.server.BayeuxServerImpl#handle2
private void handle2(ServerSessionImpl session, ServerMessage.Mutable message, ServerChannelImpl channel, Promise<ServerMessage.Mutable> promise) { ServerMessage.Mutable reply = message.getAssociated(); //是否是/meta 內置協議開頭的channel if (channel.isMeta()) { //消息處理 publish(session, channel, message, true, Promise.from(published -> promise.succeed(reply), promise::fail)); } else { //校驗是否有權限推送 isPublishAuthorized(channel, session, message, Promise.from(result -> { if (result instanceof Authorizer.Result.Denied) { String denyReason = ((Authorizer.Result.Denied)result).getReason(); error(reply, "403:" + denyReason + ":publish_denied"); promise.succeed(reply); } else { reply.setSuccessful(true); //<5>消息處理 publish(session, channel, message, true, Promise.from(published -> promise.succeed(reply), promise::fail)); } }, promise::fail)); } }
<5>
org.cometd.server.BayeuxServerImpl#publish
protected void publish(ServerSessionImpl session, ServerChannelImpl channel, ServerMessage.Mutable message, boolean receiving, Promise<Boolean> promise) { if (_logger.isDebugEnabled()) { _logger.debug("< {} {}", message, session); } //channel非/meta和非/service if (channel.isBroadcast()) { // Do not leak the clientId to other subscribers // as we are now "sending" this message. message.setClientId(null); // Reset the messageId to avoid clashes with message-based transports such // as websocket whose clients may rely on the messageId to match request/responses. message.setId(null); } //觸發Listener通知 notifyListeners(session, channel, message, Promise.from(proceed -> { if (proceed) { //<6>處理消息 publish1(session, channel, message, receiving, promise); } else { ServerMessageImpl reply = (ServerMessageImpl)message.getAssociated(); if (reply != null && !reply.isHandled()) { error(reply, "404::message_deleted"); } promise.succeed(false); } }, promise::fail)); }
<6>
org.cometd.server.BayeuxServerImpl#publish1
private void publish1(ServerSessionImpl session, ServerChannelImpl channel, ServerMessage.Mutable message, boolean receiving, Promise<Boolean> promise) { //非/meta和/service/開頭的渠道 if (channel.isBroadcast() || !receiving) { extendOutgoing(session, null, message, Promise.from(result -> { if (result) { // Exactly at this point, we convert the message to JSON and therefore // any further modification will be lost. // This is an optimization so that if the message is sent to a million // subscribers, we generate the JSON only once. // From now on, user code is passed a ServerMessage reference (and not // ServerMessage.Mutable), and we attempt to return immutable data // structures, even if it is not possible to guard against all cases. // For example, it is impossible to prevent things like // ((CustomObject)serverMessage.getData()).change() or // ((Map)serverMessage.getExt().get("map")).put(). //重新格式化消息的json freeze(message); //<7>處理消息 publish2(session, channel, message, promise); } else { ServerMessage.Mutable reply = message.getAssociated(); error(reply, "404::message_deleted"); promise.succeed(false); } }, promise::fail)); } else { //<7>處理消息 publish2(session, channel, message, promise); } }
<7>
org.cometd.server.BayeuxServerImpl#publish2
private void publish2(ServerSessionImpl session, ServerChannelImpl channel, ServerMessage.Mutable message, Promise<Boolean> promise) { //是否是/meta內部協議渠道 if (channel.isMeta()) { notifyMetaHandlers(session, channel, message, promise); } else if (channel.isBroadcast()) {//非/meta和/server的渠道 //<8> notifySubscribers(session, channel, message, promise); } else { promise.succeed(true); } }
<8>
org.cometd.server.BayeuxServerImpl#notifySubscribers
private void notifySubscribers(ServerSessionImpl session, ServerChannelImpl channel, Mutable message, Promise<Boolean> promise) { Set<String> wildSubscribers = new HashSet<>(); AsyncFoldLeft.run(channel.getChannelId().getWilds(), true, (result, wildName, wildLoop) -> { //獲得channel ServerChannelImpl wildChannel = _channels.get(wildName); if (wildChannel == null) { wildLoop.proceed(result); } else { //獲得channel的訂閱者 Set<ServerSession> subscribers = wildChannel.subscribers(); if (_logger.isDebugEnabled()) { _logger.debug("Notifying {} subscribers on {}", subscribers.size(), wildChannel); } //遍歷調用訂閱者的獲取消息方法 AsyncFoldLeft.run(subscribers, true, (r, subscriber, loop) -> { if (wildSubscribers.add(subscriber.getId())) { //是否允許自己給自己發送消息 當前渠道 if (subscriber == session && !channel.isBroadcastToPublisher()) { loop.proceed(true); } else { //<9>放入消息隊列 ((ServerSessionImpl)subscriber).deliver1(session, message, Promise.from(b -> loop.proceed(true), loop::fail)); } } else { loop.proceed(r); } }, Promise.from(y -> wildLoop.proceed(true), wildLoop::fail)); } }, Promise.from(b -> { Set<ServerSession> subscribers = channel.subscribers(); if (_logger.isDebugEnabled()) { _logger.debug("Notifying {} subscribers on {}", subscribers.size(), channel); } AsyncFoldLeft.run(subscribers, true, (result, subscriber, loop) -> { if (!wildSubscribers.contains(subscriber.getId())) { if (subscriber == session && !channel.isBroadcastToPublisher()) { loop.proceed(true); } else { //<9>放入消息隊列 ((ServerSessionImpl)subscriber).deliver1(session, message, Promise.from(y -> loop.proceed(true), loop::fail)); } } else { loop.proceed(true); } }, promise); }, promise::fail) ); }
<9>
org.cometd.server.ServerSessionImpl#deliver1
protected void deliver1(ServerSession sender, ServerMessage.Mutable mutable, Promise<Boolean> promise) { if (sender == this && !isBroadcastToPublisher() && ChannelId.isBroadcast(mutable.getChannel())) { promise.succeed(false); } else { //觸發session的獲取消息前的生命週期 extendOutgoing(sender, mutable, Promise.from(message -> { if (message == null) { promise.succeed(false); } else { _bayeux.freeze(message); //獲得session listener AsyncFoldLeft.run(_listeners, true, (result, listener, loop) -> { if (listener instanceof MessageListener) { //觸發消息監聽器 notifyOnMessage((MessageListener)listener, sender, message, _bayeux.resolveLoop(loop)); } else { loop.proceed(result); } }, Promise.from(b -> { if (b) { //<11>監聽器觸發成功加入消息到隊列 deliver2(sender, message, promise); } else { promise.succeed(false); } }, promise::fail)); } }, promise::fail)); } }
<11>
org.cometd.server.ServerSessionImpl#deliver2
private void deliver2(ServerSession sender, ServerMessage.Mutable message, Promise<Boolean> promise) { //<12>將消息加入隊列 Boolean wakeup = enqueueMessage(sender, message); if (wakeup == null) { promise.succeed(false); } else { if (wakeup) { //消息是否是延遲消息 開啓延遲任務推送 if (message.isLazy()) { flushLazy(message); } else { //<13>直接推送 flush(); } } promise.succeed(true); } }
<12>
org.cometd.server.ServerSessionImpl#enqueueMessage
private Boolean enqueueMessage(ServerSession sender, ServerMessage.Mutable message) { synchronized (getLock()) { for (ServerSessionListener listener : _listeners) { if (listener instanceof QueueMaxedListener) { int maxQueueSize = _maxQueue; //當消息達到達到queueSize 通知消息回調 可以持久化到redis或者mysql if (maxQueueSize > 0 && _queue.size() >= maxQueueSize) { if (!notifyQueueMaxed((QueueMaxedListener)listener, this, _queue, sender, message)) { return null; } } } } //將消息加入queue 最終消費者回調消費則成功方法會觸發從queue裏面獲取推送 addMessage(message); //觸發已加入消息監聽器 for (ServerSessionListener listener : _listeners) { if (listener instanceof QueueListener) { notifyQueued((QueueListener)listener, sender, message); } } return _batch == 0; } }
<13>
org.cometd.server.ServerSessionImpl#flush
public void flush() { Scheduler scheduler; synchronized (getLock()) { _lazyTask.cancel(); scheduler = _scheduler; } if (_localSession == null) { // <14>消息推送的地方org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler scheduler.schedule(); } else { // Local delivery. if (hasNonLazyMessages()) { for (ServerMessage msg : takeQueue(Collections.emptyList())) { _localSession.receive(new HashMapMessage(msg), Promise.noop()); } } } }
<14>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler#schedule
@Override public void schedule() { ServerSessionImpl session = context.session; boolean metaConnectDelivery = isMetaConnectDeliveryOnly(session); // When delivering only via /meta/connect, we want to behave similarly to HTTP. // Otherwise, the scheduler is not "disabled" by cancelling the // timeout, and it will continue to deliver messages to the client. if (metaConnectDelivery || session.isTerminated()) { //當前session未超時 表示在線 if (cancelTimeout(false)) { if (_logger.isDebugEnabled()) { _logger.debug("Resuming suspended {} for {} on {}", message, session, AbstractWebSocketEndPoint.this); } //觸發ServerSession.HeartBeatListener session.notifyResumed(message, false); //<15>發送消息 注意這個this resume(context, message, this); } } else { // Avoid sending messages if this scheduler has been disabled, so that the // messages remain in the session queue until the next scheduler is set. if (taskRef.isMarked()) { Context ctx = new Context(session); ctx.sendQueue = true; ctx.metaConnectCycle = context.metaConnectCycle; flush(ctx); } } }
<15>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#resume
private void resume(Context context, ServerMessage.Mutable message, Promise<Void> promise) { ServerMessage.Mutable reply = message.getAssociated(); ServerSessionImpl session = context.session; if (session != null) { Map<String, Object> advice = session.takeAdvice(_transport); if (advice != null) { reply.put(Message.ADVICE_FIELD, advice); } if (session.isDisconnected()) { reply.getAdvice(true).put(Message.RECONNECT_FIELD, Message.RECONNECT_NONE_VALUE); } } _transport.processReply(session, reply, Promise.from(r -> { if (r != null) { context.replies.add(r); } context.sendQueue = true; context.scheduleExpiration = true; //<16>這裏的回調是this 最終會調用 org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler.succeed方法 promise.succeed(null); }, x -> scheduleExpirationAndFail(session, context.metaConnectCycle, promise, x))); }
<16>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler#succeed
public void succeed(Void result) { //<17> executeFlush(context, Promise.from(y -> {}, this::fail)); }
<17>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.WebSocketScheduler#executeFlush
private void executeFlush(Context context, Promise<Void> promise) { //<18>線程池異步觸發當前ssesion拉取消息 _transport.getBayeux().execute(() -> AbstractWebSocketEndPoint.this.flush(context, promise)); }
<18>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint#flush
protected void flush(Context context, Promise<Void> promise) { List<ServerMessage> msgs = Collections.emptyList(); ServerSessionImpl session = context.session; if (context.sendQueue && session != null) { //拉取消息 msgs = session.takeQueue(context.replies); } if (_logger.isDebugEnabled()) { _logger.debug("Flushing {}, replies={}, messages={} on {}", session, context.replies, msgs, this); } List<ServerMessage> messages = msgs; //將消息封裝成entry加入推送隊列 boolean queued = flusher.queue(new Entry(context, messages, Promise.from(y -> { promise.succeed(null); writeComplete(context, messages); }, promise::fail))); if (queued) { //<19>觸發消息消費 flusher.iterate(); } }
<19>
org.cometd.server.websocket.common.AbstractWebSocketEndPoint.Flusher#process
@Override protected Action process() { while (true) { //類型 switch (_state) { case IDLE: { synchronized (this) { _entry = _entries.poll(); } if (_logger.isDebugEnabled()) { _logger.debug("Processing {} on {}", _entry, AbstractWebSocketEndPoint.this); } if (_entry == null) { return Action.IDLE; } _state = State.HANDSHAKE; _buffer = new StringBuilder(256); break; } case HANDSHAKE: { _state = State.MESSAGES; List<ServerMessage.Mutable> replies = _entry._context.replies; if (!replies.isEmpty()) { ServerMessage.Mutable reply = replies.get(0); if (Channel.META_HANDSHAKE.equals(reply.getChannel())) { if (_logger.isDebugEnabled()) { _logger.debug("Processing handshake reply {}", reply); } List<ServerMessage> queue = _entry._queue; if (_transport.allowMessageDeliveryDuringHandshake(_session) && !queue.isEmpty()) { reply.put("x-messages", queue.size()); } _transport.getBayeux().freeze(reply); _buffer.setLength(0); _buffer.append("["); _buffer.append(toJSON(reply)); _buffer.append("]"); ++_replyIndex; AbstractWebSocketEndPoint.this.send(_session, _buffer.toString(), this); return Action.SCHEDULED; } } break; } case MESSAGES: { List<ServerMessage> messages = _entry._queue; int size = messages.size(); if (_messageIndex < size) { int batchSize = _transport.getMessagesPerFrame(); batchSize = batchSize > 0 ? Math.min(batchSize, size) : size; if (_logger.isDebugEnabled()) { _logger.debug("Processing messages, batch size {}: {}", batchSize, messages); } _buffer.setLength(0); _buffer.append("["); boolean comma = false; int endIndex = Math.min(size, _messageIndex + batchSize); while (_messageIndex < endIndex) { ServerMessage message = messages.get(_messageIndex); if (comma) { _buffer.append(","); } comma = true; _buffer.append(toJSON(message)); ++_messageIndex; } _buffer.append("]"); //<20>發送消息 AbstractWebSocketEndPoint.this.send(_session, _buffer.toString(), this); return Action.SCHEDULED; } // Start the interval timeout after writing the // messages since they may take time to be written. _entry.scheduleExpiration(); _state = State.REPLIES; break; } case REPLIES: { List<ServerMessage.Mutable> replies = _entry._context.replies; int size = replies.size(); if (_replyIndex < size) { if (_logger.isDebugEnabled()) { _logger.debug("Processing replies {}", replies); } _buffer.setLength(0); _buffer.append("["); boolean comma = false; while (_replyIndex < size) { ServerMessage.Mutable reply = replies.get(_replyIndex); _transport.getBayeux().freeze(reply); if (comma) { _buffer.append(","); } comma = true; _buffer.append(toJSON(reply)); ++_replyIndex; } _buffer.append("]"); AbstractWebSocketEndPoint.this.send(_session, _buffer.toString(), this); return Action.SCHEDULED; } _state = State.COMPLETE; break; } case COMPLETE: { Entry entry = _entry; _state = State.IDLE; // Do not keep the buffer around while we are idle. _buffer = null; _entry = null; _messageIndex = 0; _replyIndex = 0; entry._promise.succeed(null); break; } default: { throw new IllegalStateException("Invalid state " + _state); } } } }
<20>
org.cometd.server.websocket.javax.WebSocketEndPoint.Delegate#send
@Override protected void send(ServerSession session, String data, Callback callback) { if (_logger.isDebugEnabled()) { _logger.debug("Sending {} on {}", data, this); } // Async write. 這個session是websocket的session 觸發推送 _wsSession.getAsyncRemote().sendText(data, result -> { Throwable failure = result.getException(); if (failure == null) { callback.succeeded(); } else { callback.failed(failure); } }); }