activeMq发送消息流程
1,发送消息入口
Message message = messageBean.getMessageCreator().createMessage(session);
producer.send(message);
2,调用ActiveMQMessageProducerSupport的send方法。
该类实现了MessageProducer接口
public void send(Message message) throws JMSException {
this.send(this.getDestination(),
message,
this.defaultDeliveryMode,
this.defaultPriority,
this.defaultTimeToLive);
}
public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, AsyncCallback onComplete) throws JMSException {
checkClosed();
if (destination == null) {
if (info.getDestination() == null) {
throw new UnsupportedOperationException("A destination must be specified.");
}
throw new InvalidDestinationException("Don't understand null destinations");
}
ActiveMQDestination dest;
if (destination.equals(info.getDestination())) {
dest = (ActiveMQDestination)destination;
} else if (info.getDestination() == null) {
dest = ActiveMQDestination.transform(destination);
} else {
throw new UnsupportedOperationException("This producer can only send messages to: " + this.info.getDestination().getPhysicalName());
}
if (dest == null) {
throw new JMSException("No destination specified");
}
if (transformer != null) {
Message transformedMessage = transformer.producerTransform(session, this, message);
if (transformedMessage != null) {
message = transformedMessage;
}
}
if (producerWindow != null) {
try {
producerWindow.waitForSpace();
} catch (InterruptedException e) {
throw new JMSException("Send aborted due to thread interrupt.");
}
}
this.session.send(this, dest, message, deliveryMode, priority, timeToLive, producerWindow, sendTimeout, onComplete);
stats.onMessage();
}
3调用ActiveMQSession的send接口进行消息发送
protected void send(ActiveMQMessageProducer producer, ActiveMQDestination destination, Message message, int deliveryMode, int priority, long timeToLive,
MemoryUsage producerWindow, int sendTimeout, AsyncCallback onComplete) throws JMSException { checkClosed();
if (destination.isTemporary() && connection.isDeleted(destination)) {
throw new InvalidDestinationException("Cannot publish to a deleted Destination: " + destination);
}
synchronized (sendMutex) {
// tell the Broker we are about to start a new transaction
doStartTransaction();
TransactionId txid = transactionContext.getTransactionId();
long sequenceNumber = producer.getMessageSequence(); //Set the "JMS" header fields on the original message, see 1.1 spec section 3.4.11
message.setJMSDeliveryMode(deliveryMode);
long expiration = 0L;
if (!producer.getDisableMessageTimestamp()) {
long timeStamp = System.currentTimeMillis();
message.setJMSTimestamp(timeStamp);
if (timeToLive > 0) {
expiration = timeToLive + timeStamp;
}
}
message.setJMSExpiration(expiration);
message.setJMSPriority(priority);
message.setJMSRedelivered(false); // transform to our own message format here
ActiveMQMessage msg = ActiveMQMessageTransformation.transformMessage(message, connection); // Set the message id.
if (msg == message) {
msg.setMessageId(new MessageId(producer.getProducerInfo().getProducerId(), sequenceNumber));
} else {
msg.setMessageId(new MessageId(producer.getProducerInfo().getProducerId(), sequenceNumber));
message.setJMSMessageID(msg.getMessageId().toString());
}
//clear the brokerPath in case we are re-sending this message
msg.setBrokerPath(null);
// destination format is provider specific so only set on transformed message
msg.setJMSDestination(destination); msg.setTransactionId(txid);
if (connection.isCopyMessageOnSend()) {
msg = (ActiveMQMessage)msg.copy();
}
msg.setConnection(connection);
msg.onSend();
msg.setProducerId(msg.getMessageId().getProducerId());
if (LOG.isTraceEnabled()) {
LOG.trace(getSessionId() + " sending message: " + msg);
}
if (onComplete==null && sendTimeout <= 0 && !msg.isResponseRequired() && !connection.isAlwaysSyncSend() && (!msg.isPersistent() || connection.isUseAsyncSend() || txid != null)) {
this.connection.asyncSendPacket(msg);
if (producerWindow != null) {
// Since we defer lots of the marshaling till we hit the
// wire, this might not
// provide and accurate size. We may change over to doing
// more aggressive marshaling,
// to get more accurate sizes.. this is more important once
// users start using producer window
// flow control.
int size = msg.getSize();
producerWindow.increaseUsage(size);
}
} else {
if (sendTimeout > 0 && onComplete==null) {
this.connection.syncSendPacket(msg,sendTimeout);
}else {
this.connection.syncSendPacket(msg, onComplete);
}
} }
}
4,ActiveMQConnection发送消息
public Response syncSendPacket(Command command) throws JMSException {
if (isClosed()) {
throw new ConnectionClosedException();
} else {
try {
Response response = (Response)this.transport.request(command);
if (response.isException()) {
ExceptionResponse er = (ExceptionResponse)response;
if (er.getException() instanceof JMSException) {
throw (JMSException)er.getException();
} else {
if (isClosed()||closing.get()) {
LOG.debug("Received an exception but connection is closing");
}
JMSException jmsEx = null;
try {
jmsEx = JMSExceptionSupport.create(er.getException());
} catch(Throwable e) {
LOG.error("Caught an exception trying to create a JMSException for " +er.getException(),e);
}
//dispose of transport for security exceptions
if (er.getException() instanceof SecurityException && command instanceof ConnectionInfo){
Transport t = this.transport;
if (null != t){
ServiceSupport.dispose(t);
}
}
if (jmsEx !=null) {
throw jmsEx;
}
}
}
return response;
} catch (IOException e) {
throw JMSExceptionSupport.create(e);
}
}
}
public Response syncSendPacket(Command command) throws JMSException {
if (isClosed()) {
throw new ConnectionClosedException();
} else {
try {
Response response = (Response)this.transport.request(command);
if (response.isException()) {
ExceptionResponse er = (ExceptionResponse)response;
if (er.getException() instanceof JMSException) {
throw (JMSException)er.getException();
} else {
if (isClosed()||closing.get()) {
LOG.debug("Received an exception but connection is closing");
}
JMSException jmsEx = null;
try {
jmsEx = JMSExceptionSupport.create(er.getException());
} catch(Throwable e) {
LOG.error("Caught an exception trying to create a JMSException for " +er.getException(),e);
}
//dispose of transport for security exceptions
if (er.getException() instanceof SecurityException && command instanceof ConnectionInfo){
Transport t = this.transport;
if (null != t){
ServiceSupport.dispose(t);
}
}
if (jmsEx !=null) {
throw jmsEx;
}
}
}
return response;
} catch (IOException e) {
throw JMSExceptionSupport.create(e);
}
}
}
5,ResponseCorrelator发送request
public Object request(Object command) throws IOException {
FutureResponse response = asyncRequest(command, null);
return response.getResult();
}
public FutureResponse asyncRequest(Object o, ResponseCallback responseCallback) throws IOException {
Command command = (Command) o;
command.setCommandId(sequenceGenerator.getNextSequenceId());
command.setResponseRequired(true);
FutureResponse future = new FutureResponse(responseCallback);
IOException priorError = null;
synchronized (requestMap) {
priorError = this.error;
if (priorError == null) {
requestMap.put(new Integer(command.getCommandId()), future);
}
}
if (priorError != null) {
future.set(new ExceptionResponse(priorError));
throw priorError;
}
next.oneway(command);
return future;
}
6,调用MutexTransport来发送消息
@Override
public void oneway(Object command) throws IOException {
writeLock.lock();
try {
next.oneway(command);
} finally {
writeLock.unlock();
}
}
7,调用AbstractInactivityMonitor完毕消息发送准备
public void oneway(Object o) throws IOException {
// To prevent the inactivity monitor from sending a message while we
// are performing a send we take a read lock. The inactivity monitor
// sends its Heart-beat commands under a write lock. This means that
// the MutexTransport is still responsible for synchronizing sends
this.sendLock.readLock().lock();
inSend.set(true);
try {
doOnewaySend(o);
} finally {
commandSent.set(true);
inSend.set(false);
this.sendLock.readLock().unlock();
}
}
private void doOnewaySend(Object command) throws IOException {
if( failed.get() ) {
throw new InactivityIOException("Cannot send, channel has already failed: "+next.getRemoteAddress());
}
if (command.getClass() == WireFormatInfo.class) {
synchronized (this) {
processOutboundWireFormatInfo((WireFormatInfo) command);
}
}
next.oneway(command);
}
8。调用TcpTransport。OpenWireFormat,DataOutputStream终于完毕通过tcp发送消息
public void oneway(Object command) throws IOException {
checkStarted();
wireFormat.marshal(command, dataOut);
dataOut.flush();
}
public synchronized void marshal(Object o, DataOutput dataOut) throws IOException {
if (cacheEnabled) {
runMarshallCacheEvictionSweep();
}
int size = 1;
if (o != null) {
DataStructure c = (DataStructure)o;
byte type = c.getDataStructureType();
DataStreamMarshaller dsm = (DataStreamMarshaller)dataMarshallers[type & 0xFF];
if (dsm == null) {
throw new IOException("Unknown data type: " + type);
}
if (tightEncodingEnabled) {
BooleanStream bs = new BooleanStream();
size += dsm.tightMarshal1(this, c, bs);
size += bs.marshalledSize();
if (!sizePrefixDisabled) {
dataOut.writeInt(size);
}
dataOut.writeByte(type);
bs.marshal(dataOut);
dsm.tightMarshal2(this, c, dataOut, bs);
} else {
DataOutput looseOut = dataOut;
if (!sizePrefixDisabled) {
bytesOut.restart();
looseOut = bytesOut;
}
looseOut.writeByte(type);
dsm.looseMarshal(this, c, looseOut);
if (!sizePrefixDisabled) {
ByteSequence sequence = bytesOut.toByteSequence();
dataOut.writeInt(sequence.getLength());
dataOut.write(sequence.getData(), sequence.getOffset(), sequence.getLength());
}
}
} else {
if (!sizePrefixDisabled) {
dataOut.writeInt(size);
}
dataOut.writeByte(NULL_TYPE);
}
}
public final void writeInt(int v) throws IOException {
out.write((v >>> 24) & 0xFF);
out.write((v >>> 16) & 0xFF);
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(4);
}
附图
备注:MessageId是通过ProducerId+sequenceNumber来生成的,sequenceNumber通过原子变量的加1完毕
activeMq发送消息流程的更多相关文章
- 【Java Web开发学习】Spring消息-ActiveMQ发送消息
ActiveMQ发送消息 转载:http://www.cnblogs.com/yangchongxing/p/9042401.html Java消息服务(Java Message Service, J ...
- KafkaProducer 发送消息流程
Kafka 的 Producer 发送消息采用的是异步发送的方式.在消息发送的过程中,涉及到了 两个线程--main 线程和 Sender 线程,以及一个线程共享变量--RecordAccumulat ...
- jmeter向ActiveMQ发送消息_广播/订阅(Topics 队列)
问题描述:测试中需要模拟大量设备的消息上报到平台,但是实际测试中没有那么多设备,所以采取用jmeter直接往ActiveMQ模拟发送设备消息 解决思路:获取平台采取的是Queues还是Topics : ...
- 新浪微博发送消息和授权机制原理(WeiboSDK)
1.首先是在微博发送消息,对于刚開始做weibo发送消息的刚開始学习的人会有一个误区,那就是会觉得须要授权后才干够发送消息.事实上发送消息仅仅须要几行代码就能够实现了,很easy,不须要先授权再发送消 ...
- ActiveMQ producer不断发送消息,会导致broker内存耗尽吗?
http://activemq.apache.org/my-producer-blocks.html 回答了这个问题: ActiveMQ 5.x 支持Message Cursors,它默认把消息从内存 ...
- ActiveMQ producer同步/异步发送消息
http://activemq.apache.org/async-sends.html producer发送消息有同步和异步两种模式,可以通过代码配置: ((ActiveMQConnection)co ...
- ACtiveMQ中间件-消息的接收和发送
一.发送消息基本步骤 (1)启动ActiveMQ的的activemq.bat批处理文件或BrokerService节点 (2)创建连接使用的工厂类ActiveMQConnectionFactory通过 ...
- php 事务处理,ActiveMQ的发送消息,与处理消息
可以通过链式发送->处理->发送...的方式处理类似事务型业务逻辑 比如 发送一个注册消息,消息队列处理完注册以后,紧接着发送一个新手优惠券赠送,赠送完再发一个其它后续逻辑处理的消息等待后 ...
- ActiveMQ实现消息的发送与接受
activemq是apache的一个JMS接口的实现产品,java中定义了JMS规范,虽然RocketMQ,kafka现在比较火,但是还是建议先学一下activeMQ再学其他两个就容易很多 首先可以下 ...
随机推荐
- Sqli-labs介绍、下载、安装
SQLI和sqli-labs介绍 SQLI,sql injection,我们称之为sql注入.何为sql,英文:Structured Query Language,叫做结构化查询语言.常见的结构化数据 ...
- Mixins 改成使用高阶组件调用
把组件放在另外一个组件的 render 方法里面, 并且利用了 {...this.props} {...this.state} 这些 JSX 展开属性 对比下2种代码: 原始方式: <!DOC ...
- Struts2中的设计模式
http://blog.csdn.net/significantfrank/article/details/7712053 1. Command Pattern 基本定义: 把Command(Requ ...
- WebService的网络协议
SOAP协议.XML-RPC以及Hessian 是WebService的主要传输(编码)协议 SOAP即简单对象访问协议(Simple Object Access Protocol),它是用于交换XM ...
- 【构造】【贪心】hdu6090 Rikka with Graph
给你n个点,让你连m条边,使得任意两两点对之间的最短路的和最小(两点若不可达,最短路记作n). 初始时ans=n*n*(n-1). 先尽量连成菊花图,每连一次让答案减小2*((n-2)*(i-1)+( ...
- 【推导】Codeforces Round #410 (Div. 2) C. Mike and gcd problem
如果一开始就满足题意,不用变换. 否则,如果对一对ai,ai+1用此变换,设新的gcd为d,则有(ai - ai+1)mod d = 0,(ai + ai+1)mod d = 0 变化一下就是2 ai ...
- mybatis批量update,返回行数为-1
mybatis批量更新返回结果为-1,是由于mybatis的defaultExExecutorType引起的, 它有三个执行器:SIMPLE 就是普通的执行器:REUSE 执行器会重用预处理语句 ...
- session cookie的区别最全总结
作为一名WEB开发程序员,对session的理解是最基础的,但是现状是WEB程序员遍地都是,随便一划拉一大把,不过估计能把session能透彻理解的人应该不是很多,起码我之前对此是知之甚少,偶然看到的 ...
- BUG:php7.1 访问yii数据库 自动加端口3306 报错
跟新完php7.1后访问yii项目出现下图错误 可见数据库链接是已经制指定了端口号9004 但是访问时后续自动加上了3306 原因:换了方式 //这种方式只支持5.6版本php 'db' => ...
- JAVA EE 中之AJAX 无刷新地区下拉列表三级联动
JSP页面 <html> <head> <meta http-equiv="Content-Type" content="text/html ...