在发送和接收消息重要的类有:ConnectionFactory, Connection,Channel和 QueueingConsumer。
ConntectionFactory类是方便创建与AMQP代理相关联的Connection;下面来看看ConntectionFactory是如何创建一个Contention.首先通过new ConnectionFactory()创建一个ConnectionFactory;并设置此连接工厂的主机设置为broke IP。通过ConnectionFactory的newConnection()方法 创建一个Connection; newConnection方法通过得到当前连接的地址及端口号来获得一个Address,通过createFrameHandler的方法
来得到FrameHandler;再通过new AMQConnection(this, frameHandler)来得到Connection并启动。
代码清单1创建Connection的源码(ConnectionFactory.java中)
protected FrameHandler createFrameHandler(Address addr)
throws IOException {
String hostName = addr.getHost();//获取主机IP
int portNumber = portOrDefault(addr.getPort());//获取端口
Socket socket = null;
try {
socket = factory.createSocket();
configureSocket(socket);
socket.connect(new InetSocketAddress(hostName, portNumber),
connectionTimeout);
return createFrameHandler(socket);
} catch (IOException ioe) {
quietTrySocketClose(socket);
throw ioe;
}
}
private static void quietTrySocketClose(Socket socket) {
if (socket != null)
try { socket.close(); } catch (Exception _) {/*ignore exceptions*/}
}
protected FrameHandler createFrameHandler(Socket sock)
throws IOException
{
return new SocketFrameHandler(sock);
}
/**
* Provides a hook to insert custom configuration of the sockets
* used to connect to an AMQP server before they connect.
*
* The default behaviour of this method is to disable Nagle's
* algorithm to get more consistently low latency. However it
* may be overridden freely and there is no requirement to retain
* this behaviour.
*
* @param socket The socket that is to be used for the Connection
*/
protected void configureSocket(Socket socket) throws IOException{
// disable Nagle's algorithm, for more consistently low latency
socket.setTcpNoDelay(true);
}
/**
* Create a new broker connection
* @param addrs an array of known broker addresses (hostname/port pairs) to try in order
* @return an interface to the connection
* @throws IOException if it encounters a problem
*/
public Connection newConnection(Address[] addrs) throws IOException {
return newConnection(null, addrs);
}
/**
* Create a new broker connection
* @param executor thread execution service for consumers on the connection
* @param addrs an array of known broker addresses (hostname/port pairs) to try in order
* @return an interface to the connection
* @throws IOException if it encounters a problem
*/
public Connection newConnection(ExecutorService executor, Address[] addrs)
throws IOException
{
IOException lastException = null;
for (Address addr : addrs) {
try {
FrameHandler frameHandler = createFrameHandler(addr);
AMQConnection conn =
new AMQConnection(username,
password,
frameHandler,
executor,
virtualHost,
getClientProperties(),
requestedFrameMax,
requestedChannelMax,
requestedHeartbeat,
saslConfig);
conn.start();
return conn;
} catch (IOException e) {
lastException = e;
}
}
throw (lastException != null) ? lastException
: new IOException("failed to connect");
}
/**
* Create a new broker connection
* @return an interface to the connection
* @throws IOException if it encounters a problem
*/
public Connection newConnection() throws IOException {
return newConnection(null,
new Address[] {new Address(getHost(), getPort())}
);
}
/**
* Create a new broker connection
* @param executor thread execution service for consumers on the connection
* @return an interface to the connection
* @throws IOException if it encounters a problem
*/
public Connection newConnection(ExecutorService executor) throws IOException {
return newConnection(executor,
new Address[] {new Address(getHost(), getPort())}
);
}
代码清单2 连接启动/**
* Start up the connection, including the MainLoop thread.
* Sends the protocol
* version negotiation header, and runs through
* Connection.Start/.StartOk, Connection.Tune/.TuneOk, and then
* calls Connection.Open and waits for the OpenOk. Sets heart-beat
* and frame max values after tuning has taken place.
* @throws IOException if an error is encountered
* either before, or during, protocol negotiation;
* sub-classes {@link ProtocolVersionMismatchException} and
* {@link PossibleAuthenticationFailureException} will be thrown in the
* corresponding circumstances. If an exception is thrown, connection
* resources allocated can all be garbage collected when the connection
* object is no longer referenced.
*/
public void start()
throws IOException
{
this._running = true;
// Make sure that the first thing we do is to send the header,
// which should cause any socket errors to show up for us, rather
// than risking them pop out in the MainLoop
AMQChannel.SimpleBlockingRpcContinuation connStartBlocker =
new AMQChannel.SimpleBlockingRpcContinuation();
// We enqueue an RPC continuation here without sending an RPC
// request, since the protocol specifies that after sending
// the version negotiation header, the client (connection
// initiator) is to wait for a connection.start method to
// arrive.
_channel0.enqueueRpc(connStartBlocker);
try {
// The following two lines are akin to AMQChannel's
// transmit() method for this pseudo-RPC.
_frameHandler.setTimeout(HANDSHAKE_TIMEOUT);
_frameHandler.sendHeader();
} catch (IOException ioe) {
_frameHandler.close();
throw ioe;
}
// start the main loop going
new MainLoop("AMQP Connection " + getHostAddress() + ":" + getPort()).start();
// after this point clear-up of MainLoop is triggered by closing the frameHandler.
AMQP.Connection.Start connStart = null;
AMQP.Connection.Tune connTune = null;
try {
connStart =
(AMQP.Connection.Start) connStartBlocker.getReply().getMethod();
_serverProperties = Collections.unmodifiableMap(connStart.getServerProperties());
Version serverVersion =
new Version(connStart.getVersionMajor(),
connStart.getVersionMinor());
if (!Version.checkVersion(clientVersion, serverVersion)) {
throw new ProtocolVersionMismatchException(clientVersion,
serverVersion);
}
String[] mechanisms = connStart.getMechanisms().toString().split(" ");
SaslMechanism sm = this.saslConfig.getSaslMechanism(mechanisms);
if (sm == null) {
throw new IOException("No compatible authentication mechanism found - " +
"server offered [" + connStart.getMechanisms() + "]");
}
LongString challenge = null;
LongString response = sm.handleChallenge(null, this.username, this.password);
do {
Method method = (challenge == null)
? new AMQP.Connection.StartOk.Builder()
.clientProperties(_clientProperties)
.mechanism(sm.getName())
.response(response)
.build()
: new AMQP.Connection.SecureOk.Builder().response(response).build();
try {
Method serverResponse = _channel0.rpc(method).getMethod();
if (serverResponse instanceof AMQP.Connection.Tune) {
connTune = (AMQP.Connection.Tune) serverResponse;
} else {
challenge = ((AMQP.Connection.Secure) serverResponse).getChallenge();
response = sm.handleChallenge(challenge, this.username, this.password);
}
} catch (ShutdownSignalException e) {
throw new PossibleAuthenticationFailureException(e);
}
} while (connTune == null);
} catch (ShutdownSignalException sse) {
_frameHandler.close();
throw AMQChannel.wrap(sse);
} catch(IOException ioe) {
_frameHandler.close();
throw ioe;
}
try {
int channelMax =
negotiatedMaxValue(this.requestedChannelMax,
connTune.getChannelMax());
_channelManager = new ChannelManager(this._workService, channelMax);
int frameMax =
negotiatedMaxValue(this.requestedFrameMax,
connTune.getFrameMax());
this._frameMax = frameMax;
int heartbeat =
negotiatedMaxValue(this.requestedHeartbeat,
connTune.getHeartbeat());
setHeartbeat(heartbeat);
_channel0.transmit(new AMQP.Connection.TuneOk.Builder()
.channelMax(channelMax)
.frameMax(frameMax)
.heartbeat(heartbeat)
.build());
_channel0.exnWrappingRpc(new AMQP.Connection.Open.Builder()
.virtualHost(_virtualHost)
.build());
} catch (IOException ioe) {
_heartbeatSender.shutdown();
_frameHandler.close();
throw ioe;
} catch (ShutdownSignalException sse) {
_heartbeatSender.shutdown();
_frameHandler.close();
throw AMQChannel.wrap(sse);
}
// We can now respond to errors having finished tailoring the connection
this._inConnectionNegotiation = false;
return;
}
转载:http://wubin850219.iteye.com/blog/1007984