首先看一下activemq的网络模型(获取自网络)。
可以看到,TcpTransportServer是一个监听网络的类,如果有socket连接,便会放入阻塞队列,然后创建一个TransportConnection类,该类接收socket的消息,进行逻辑处理;
先看看TransportConnector在干啥
第一步:设置server处理类
第二步:接收到连接socket加入线程池
第三步:创建一个连接
第四步:连接启动
最终会调用到getServer().start();在看看TcpTransportServer在干啥
/**
* pull Sockets from the ServerSocket
*/
@Override
public void run() {
if (!isStopped() && !isStopping()) {
final ServerSocket serverSocket = this.serverSocket;
if (serverSocket == null) {
onAcceptError(new IOException("Server started without a valid ServerSocket"));
}
final ServerSocketChannel channel = serverSocket.getChannel();
if (channel != null) {
doRunWithServerSocketChannel(channel);
} else {
doRunWithServerSocket(serverSocket);
}
}
}
会调用到
doRunWithServerSocketChannel(channel);
private void doRunWithServerSocketChannel(final ServerSocketChannel channel) {
try {
channel.configureBlocking(false);
final Selector selector = Selector.open();
try {
channel.register(selector, SelectionKey.OP_ACCEPT); // 接受连接事件
} catch (ClosedChannelException ex) {
try {
selector.close();
} catch (IOException ignore) {}
throw ex;
}
// Update object instance for later cleanup.
this.selector = selector;
while (!isStopped()) { // while循环一直等待连接
int count = selector.select(10);
if (count == 0) {
continue;
}
Set<SelectionKey> keys = selector.selectedKeys();
for (Iterator<SelectionKey> i = keys.iterator(); i.hasNext(); ) { // 遍历通道事件
final SelectionKey key = i.next();
if (key.isAcceptable()) { // 如果有连接事件
try {
SocketChannel sc = channel.accept();
if (sc != null) {
if (isStopped() || getAcceptListener() == null) {
sc.close();
} else {
if (useQueueForAccept) {
socketQueue.put(sc.socket()); // 放入阻塞队列
} else {
handleSocket(sc.socket()); // 直接获取
}
}
}
} catch (SocketTimeoutException ste) {
// expect this to happen
} catch (Exception e) {
e.printStackTrace();
if (!isStopping()) {
onAcceptError(e);
} else if (!isStopped()) {
LOG.warn("run()", e);
onAcceptError(e);
}
}
}
i.remove();
}
}
} catch (IOException ex) {
if (!isStopping()) {
onAcceptError(ex);
} else if (!isStopped()) {
LOG.warn("run()", ex);
onAcceptError(ex);
}
}
}
如果是直接处理
final protected void doHandleSocket(Socket socket) {
boolean closeSocket = true;
boolean countIncremented = false;
try {
int currentCount;
do {
currentCount = currentTransportCount.get();
if (currentCount >= this.maximumConnections) {
throw new ExceededMaximumConnectionsException(
"Exceeded the maximum number of allowed client connections. See the '" +
"maximumConnections' property on the TCP transport configuration URI " +
"in the ActiveMQ configuration file (e.g., activemq.xml)");
}
//Increment this value before configuring the transport
//This is necessary because some of the transport servers must read from the
//socket during configureTransport() so we want to make sure this value is
//accurate as the transport server could pause here waiting for data to be sent from a client
} while(!currentTransportCount.compareAndSet(currentCount, currentCount + 1));
countIncremented = true;
HashMap<String, Object> options = new HashMap<String, Object>();
options.put("maxInactivityDuration", Long.valueOf(maxInactivityDuration));
options.put("maxInactivityDurationInitalDelay", Long.valueOf(maxInactivityDurationInitalDelay));
options.put("minmumWireFormatVersion", Integer.valueOf(minmumWireFormatVersion));
options.put("trace", Boolean.valueOf(trace));
options.put("soTimeout", Integer.valueOf(soTimeout));
options.put("socketBufferSize", Integer.valueOf(socketBufferSize));
options.put("connectionTimeout", Integer.valueOf(connectionTimeout));
options.put("logWriterName", logWriterName);
options.put("dynamicManagement", Boolean.valueOf(dynamicManagement));
options.put("startLogging", Boolean.valueOf(startLogging));
options.putAll(transportOptions);
TransportInfo transportInfo = configureTransport(this, socket);
closeSocket = false;
if (transportInfo.transport instanceof ServiceSupport) {
((ServiceSupport) transportInfo.transport).addServiceListener(this);
}
Transport configuredTransport = transportInfo.transportFactory.serverConfigure(
transportInfo.transport, transportInfo.format, options);
getAcceptListener().onAccept(configuredTransport); // 调用上面置入的TransportAcceptListener的onAccept方法
} catch (SocketTimeoutException ste) {
// expect this to happen
} catch (Exception e) {
if (closeSocket) {
try {
//if closing the socket, only decrement the count it was actually incremented
//where it was incremented
if (countIncremented) {
currentTransportCount.decrementAndGet();
}
socket.close();
} catch (Exception ignore) {
}
}
if (!isStopping()) {
onAcceptError(e);
} else if (!isStopped()) {
LOG.warn("run()", e);
onAcceptError(e);
}
}
}
@Override
public void start() throws Exception {
broker = brokerService.getBroker();
brokerInfo.setBrokerName(broker.getBrokerName());
brokerInfo.setBrokerId(broker.getBrokerId());
brokerInfo.setPeerBrokerInfos(broker.getPeerBrokerInfos());
brokerInfo.setFaultTolerantConfiguration(broker.isFaultTolerantConfiguration());
brokerInfo.setBrokerURL(broker.getBrokerService().getDefaultSocketURIString());
getServer().setAcceptListener(new TransportAcceptListener() {
@Override
// 调用到这个方法
public void onAccept(final Transport transport) {
try {
brokerService.getTaskRunnerFactory().execute(new Runnable() {
@Override
public void run() {
try {
if (!brokerService.isStopping()) {
Connection connection = createConnection(transport);
connection.start();
} else {
throw new BrokerStoppedException("Broker " + brokerService + " is being stopped");
}
} catch (Exception e) {
String remoteHost = transport.getRemoteAddress();
ServiceSupport.dispose(transport);
onAcceptError(e, remoteHost);
}
}
});
} catch (Exception e) {
String remoteHost = transport.getRemoteAddress();
ServiceSupport.dispose(transport);
onAcceptError(e, remoteHost);
}
}
@Override
public void onAcceptError(Exception error) {
onAcceptError(error, null);
}
private void onAcceptError(Exception error, String remoteHost) {
if (brokerService != null && brokerService.isStopping()) {
LOG.info("Could not accept connection during shutdown {} : {}", (remoteHost == null ? "" : "from " + remoteHost), error);
} else {
LOG.error("Could not accept connection {} : {}", (remoteHost == null ? "" : "from " + remoteHost), error);
LOG.debug("Reason: " + error, error);
}
}
});
getServer().setBrokerInfo(brokerInfo);
getServer().start();
DiscoveryAgent da = getDiscoveryAgent();
if (da != null) {
da.registerService(getPublishableConnectString());
da.start();
}
if (enableStatusMonitor) {
this.statusDector = new TransportStatusDetector(this);
this.statusDector.start();
}
LOG.info("Connector {} started", getName());
}
看看TcpTransportConnection的start方法
@Override
public void start() throws Exception {
try {
synchronized (this) {
starting.set(true);
if (taskRunnerFactory != null) {
taskRunner = taskRunnerFactory.createTaskRunner(this, "ActiveMQ Connection Dispatcher: "
+ getRemoteAddress());
} else {
taskRunner = null;
}
// 从下面的截图看看真实的实现类
transport.start();
active = true;
BrokerInfo info = connector.getBrokerInfo().copy();
if (connector.isUpdateClusterClients()) {
info.setPeerBrokerInfos(this.broker.getPeerBrokerInfos());
} else {
info.setPeerBrokerInfos(null);
}
dispatchAsync(info);
connector.onStarted(this);
}
} catch (Exception e) {
// Force clean up on an error starting up.
pendingStop.set(true);
throw e;
} finally {
// stop() can be called from within the above block,
// but we want to be sure start() completes before
// stop() runs, so queue the stop until right now:
setStarting(false);
if (isPendingStop()) {
LOG.debug("Calling the delayed stop() after start() {}", this);
stop();
}
}
}
会调用到TcpTransport的这个方法
@Override
protected void doStart() throws Exception {
connect();
stoppedLatch.set(new CountDownLatch(1));
super.doStart();
}
protected void connect() throws Exception {
if (socket == null && socketFactory == null) {
throw new IllegalStateException("Cannot connect if the socket or socketFactory have not been set");
}
InetSocketAddress localAddress = null;
InetSocketAddress remoteAddress = null;
if (localLocation != null) {
localAddress = new InetSocketAddress(InetAddress.getByName(localLocation.getHost()),
localLocation.getPort());
}
if (remoteLocation != null) {
String host = resolveHostName(remoteLocation.getHost());
remoteAddress = new InetSocketAddress(host, remoteLocation.getPort());
}
// Set the traffic class before the socket is connected when possible so
// that the connection packets are given the correct traffic class.
this.trafficClassSet = setTrafficClass(socket);
if (socket != null) {
if (localAddress != null) {
socket.bind(localAddress);
}
// If it's a server accepted socket.. we don't need to connect it
// to a remote address.
if (remoteAddress != null) {
if (connectionTimeout >= 0) {
socket.connect(remoteAddress, connectionTimeout);
} else {
socket.connect(remoteAddress);
}
}
} else {
// For SSL sockets.. you can't create an unconnected socket :(
// This means the timout option are not supported either.
if (localAddress != null) {
socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort(),
localAddress.getAddress(), localAddress.getPort());
} else {
socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort());
}
}
initialiseSocket(socket);
initializeStreams();
}
启动TcpTransport的start方法
protected void doStart() throws Exception {
runner = new Thread(null, this, "ActiveMQ Transport: " + toString(), stackSize);
runner.setDaemon(daemon);
runner.start();
}
/**
* reads packets from a Socket
*/
@Override
public void run() {
LOG.trace("TCP consumer thread for " + this + " starting");
this.runnerThread=Thread.currentThread();
try {
while (!isStopped()) {
doRun();
}
} catch (IOException e) {
stoppedLatch.get().countDown();
onException(e);
} catch (Throwable e){
stoppedLatch.get().countDown();
IOException ioe=new IOException("Unexpected error occurred: " + e);
ioe.initCause(e);
onException(ioe);
}finally {
stoppedLatch.get().countDown();
}
}
接收客户端的传过来的消息
protected void doRun() throws IOException {
try {
Object command = readCommand();
doConsume(command);
} catch (SocketTimeoutException e) {
} catch (InterruptedIOException e) {
}
}
连上之后,以下是broker从producter接收到的消息
WireFormatInfo { version=12, properties={MaxFrameSize=9223372036854775807, CacheSize=1024, ProviderVersion=5.14.6-SNAPSHOT, CacheEnabled=true, Host=localhost, ProviderName=ActiveMQ, SizePrefixDisabled=false, TcpNoDelayEnabled=true, PlatformDetails=JVM: 1.7.0_79, 24.79-b02, Oracle Corporation, OS: Windows 7, 6.1, amd64, MaxInactivityDurationInitalDelay=10000, MaxInactivityDuration=30000, TightEncodingEnabled=true, StackTraceEnabled=true}, magic=[A,c,t,i,v,e,M,Q]}
ConnectionInfo {commandId = 1, responseRequired = true, connectionId = ID:, clientId = ID:, clientIp = null, userName = null, password = , brokerPath = null, brokerMasterConnector = false, manageable = true, clientMaster = true, faultTolerant = false, failoverReconnect = false}
ConsumerInfo {commandId = 2, responseRequired = true, consumerId = ID:, destination = ActiveMQ.Advisory.TempQueue,ActiveMQ.Advisory.TempTopic, prefetchSize = 1000, maximumPendingMessageLimit = 0, browser = false, dispatchAsync = true, selector = null, clientId = null, subscriptionName = null, noLocal = true, exclusive = false, retroactive = false, priority = 0, brokerPath = null, optimizedAcknowledge = false, noRangeAcks = false, additionalPredicate = null}
KeepAliveInfo {}
SessionInfo {commandId = 3, responseRequired = false, sessionId = ID:}
ProducerInfo {commandId = 4, responseRequired = true, producerId = ID:, destination = topic://FirstTopic, brokerPath = null, dispatchAsync = false, windowSize = 0, sentCount = 0}
TransactionInfo {commandId = 5, responseRequired = false, type = 0, connectionId = ID:, transactionId = TX:ID:}
ActiveMQTextMessage {commandId = 6, responseRequired = false, messageId = ID:, originalDestination = null, originalTransactionId = null, producerId = , destination = topic://FirstTopic, transactionId = TX:ID:, expiration = 0, timestamp = 1524029198022, arrival = 0, brokerInTime = 0, brokerOutTime = 0, correlationId = null, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = org.apache.activemq.util.ByteSequence@c80e39e, marshalledProperties = null, dataStructure = null, redeliveryCounter = 0, size = 0, properties = null, readOnlyProperties = false, readOnlyBody = false, droppable = false, jmsXGroupFirstForConsumer = false, text = ActiveMq 发送的消息}
RemoveInfo {commandId = 9, responseRequired = false, objectId = ID:, lastDeliveredSequenceId = -2}
消费消息时,进入transportsupport类的该方法, 然后会调用到TransportConnection上的设置的监听器transportListener。
/**
* Process the inbound command
*/
public void doConsume(Object command) {
if (command != null) {
//transportListener是innactivitymonitor的实例
if (transportListener != null) {
transportListener.onCommand(command);
} else {
LOG.error("No transportListener available to process inbound command: " + command);
}
}
}
看看Topic类的dispatch方法:
protected void dispatch(final ConnectionContext context, Message message) throws Exception {
// AMQ-2586: Better to leave this stat at zero than to give the user
// misleading metrics.
// destinationStatistics.getMessages().increment();
destinationStatistics.getEnqueues().increment();
destinationStatistics.getMessageSize().addSize(message.getSize());
MessageEvaluationContext msgContext = null;
dispatchLock.readLock().lock();
try {
if (!subscriptionRecoveryPolicy.add(context, message)) {
return;
}
synchronized (consumers) {
if (consumers.isEmpty()) {
onMessageWithNoConsumers(context, message);
return;
}
}
// Clear memory before dispatch - need to clear here because the call to
//subscriptionRecoveryPolicy.add() will unmarshall the state
if (isReduceMemoryFootprint() && message.isMarshalled()) {
message.clearUnMarshalledState();
}
msgContext = context.getMessageEvaluationContext();
msgContext.setDestination(destination);
msgContext.setMessageReference(message);
if (!dispatchPolicy.dispatch(message, msgContext, consumers)) {
onMessageWithNoConsumers(context, message);
}
} finally {
dispatchLock.readLock().unlock();
if (msgContext != null) {
msgContext.clear();
}
}
}
看看发送给订阅者的一个策略,轮询算法
/**
* Simple dispatch policy that sends a message to every subscription that
* matches the message.
*
* @org.apache.xbean.XBean
*
*/
public class RoundRobinDispatchPolicy implements DispatchPolicy {
/**
* @param node
* @param msgContext
* @param consumers
* @return true if dispatched
* @throws Exception
* @see org.apache.activemq.broker.region.policy.DispatchPolicy#dispatch(org.apache.activemq.broker.region.MessageReference,
* org.apache.activemq.filter.MessageEvaluationContext, java.util.List)
*/
public boolean dispatch(MessageReference node,
MessageEvaluationContext msgContext, List<Subscription> consumers)
throws Exception {
int count = 0;
Subscription firstMatchingConsumer = null;
synchronized (consumers) {
for (Iterator<Subscription> iter = consumers.iterator(); iter
.hasNext();) {
Subscription sub = iter.next();
// Only dispatch to interested subscriptions
if (!sub.matches(node, msgContext)) {
sub.unmatched(node);
continue;
}
if (firstMatchingConsumer == null) {
firstMatchingConsumer = sub;
}
sub.add(node);
count++;
}
if (firstMatchingConsumer != null) {
// Rotate the consumer list.
try {
consumers.remove(firstMatchingConsumer);
consumers.add(firstMatchingConsumer);
} catch (Throwable bestEffort) {
}
}
}
return count > 0;
}
}
默认是SimpleDispatchPolicy
/**
* Simple dispatch policy that sends a message to every subscription that
* matches the message.
*
* @org.apache.xbean.XBean
*
*/
public class SimpleDispatchPolicy implements DispatchPolicy {
public boolean dispatch(MessageReference node, MessageEvaluationContext msgContext, List<Subscription> consumers)
throws Exception {
int count = 0;
for (Subscription sub : consumers) {
// Don't deliver to browsers
if (sub.getConsumerInfo().isBrowser()) {
continue;
}
// Only dispatch to interested subscriptions
if (!sub.matches(node, msgContext)) {
sub.unmatched(node);
continue;
}
sub.add(node);
count++;
}
return count > 0;
}
}
看下面这行代码
sub.add(node);
执行到TopicSubscription类的add方法
执行到TransportConnection的dispatchAsync方法,可以看到其实是加到了dispatchQueue这个阻塞列表里,有一个专门的线程去执行。由上可知,对于topic而言,对于每条消息,会加入到所有的在线订阅者的队列上。如果订阅者不在线,是消费不到该消息的。
@Override
public void dispatchAsync(Command message) {
if (!stopping.get()) {
if (taskRunner == null) {
dispatchSync(message);
} else {
synchronized (dispatchQueue) {
dispatchQueue.add(message);
}
try {
taskRunner.wakeup();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
} else {
if (message.isMessageDispatch()) {
MessageDispatch md = (MessageDispatch) message;
TransmitCallback sub = md.getTransmitCallback();
broker.postProcessDispatch(md);
if (sub != null) {
sub.onFailure();
}
}
}
}
TaskRunner是一个线程池
public TaskRunner createTaskRunner(Task task, String name) {
init();
ExecutorService executor = executorRef.get();
if (executor != null) {
return new PooledTaskRunner(executor, task, maxIterationsPerRun);
} else {
return new DedicatedTaskRunner(task, name, priority, daemon);
}
}
跑的任务实际上是下面的迭代器方法
@Override
public boolean iterate() {
try {
if (pendingStop.get() || stopping.get()) {
if (dispatchStopped.compareAndSet(false, true)) {
if (transportException.get() == null) {
try {
dispatch(new ShutdownInfo());
} catch (Throwable ignore) {
}
}
dispatchStoppedLatch.countDown();
}
return false;
}
if (!dispatchStopped.get()) {
Command command = null;
synchronized (dispatchQueue) {
if (dispatchQueue.isEmpty()) {
return false;
}
command = dispatchQueue.remove(0);
}
processDispatch(command);
return true;
}
return false;
} catch (IOException e) {
if (dispatchStopped.compareAndSet(false, true)) {
dispatchStoppedLatch.countDown();
}
serviceExceptionAsync(e);
return false;
}
}