从前面几小节的学习,我们可能知道在发送和接收消息重要的类ConnectionFactory, Connection,Channel和 QueueingConsumer。
ConntectionFactory类是方便创建与AMQP代理相关联的Connection;下面来看看ConntectionFactory是如何创建一个Contention.
首先通过new ConnectionFactory()创建一个ConnectionFactory;并设置此连接工厂的主机设置为localhost。通过ConnectionFactory的newConnection()方法 创建一个Connection; newConnection方法通过得到当前连接的地址及端口号来获得一个Address,通过createFrameHandler的方法 来得到FrameHandler;再通过new AMQConnection(this, frameHandler)来得到Connection并启动。如代码清单7-1所示。
代码清单7-1 创建Connection的源码(ConnectionFactory.java中)
1. protected FrameHandler createFrameHandler(Address addr) 2. throws IOException { 3. 4. String hostName = addr.getHost(); 5. int portNumber = portOrDefault(addr.getPort());//得到端口号 6. Socket socket = factory.createSocket(); 7. configureSocket(socket);//这里Socket通过TCP无迟延的协议 8. socket.connect(new InetSocketAddress(hostName, portNumber), connectionTimeout); 9. return createFrameHandler(socket); 10. } 11. 12. protected FrameHandler createFrameHandler(Socket sock) 13. throws IOException 14. { 15. return new SocketFrameHandler(sock); 16. } 17. 18. /** 19. * Provides a hook to insert custom configuration of the sockets 20. * used to connect to an AMQP server before they connect. 21. * 22. * The default behaviour of this method is to disable Nagle's 23. * algorithm to get more consistently low latency. However it 24. * may be overridden freely and there is no requirement to retain 25. * this behaviour. 26. * 27. * @param socket The socket that is to be used for the Connection 28. */ 29. protected void configureSocket(Socket socket) throws IOException{ 30. // disable Nagle's algorithm, for more consistently low latency 31. socket.setTcpNoDelay(true); 32. } 33. 34. /** 35. * Create a new broker connection 36. * @param addrs an array of known broker addresses (hostname/port pairs) to try in order 37. * @return an interface to the connection 38. * @throws IOException if it encounters a problem 39. */ 40. public Connection newConnection(Address[] addrs) 41. throws IOException 42. { 43. IOException lastException = null; 44. for (Address addr : addrs) { 45. try { 46. FrameHandler frameHandler = createFrameHandler(addr); 47. AMQConnection conn = new AMQConnection(this, 48. frameHandler); 49. conn.start(); 50. return conn; 51. } catch (IOException e) { 52. lastException = e; 53. } 54. } 55. 56. if (lastException == null) { 57. throw new IOException("failed to connect"); 58. } else { 59. throw lastException; 60. } 61. } 62. 63. /** 64. * Create a new broker connection 65. * @return an interface to the connection 66. * @throws IOException if it encounters a problem 67. */ 68. public Connection newConnection() throws IOException { 69. return newConnection(new Address[] { 70. new Address(getHost(), getPort())}); 71. }
代码清单7-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 heartbeat * and frame max values after tuning has taken place. * @throws java.io.IOException if an error is encountered; IOException * subtypes {@link ProtocolVersionMismatchException} and * {@link PossibleAuthenticationFailureException} will be thrown in the * corresponding circumstances. */ public void start() throws IOException { // 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); // The following two lines are akin to AMQChannel's // transmit() method for this pseudo-RPC. _frameHandler.setTimeout(HANDSHAKE_TIMEOUT); _frameHandler.sendHeader(); // start the main loop going Thread ml = new MainLoop(); ml.setName("AMQP Connection " + getHostAddress() + ":" + getPort()); ml.start(); AMQP.Connection.Start connStart = null; try { connStart = (AMQP.Connection.Start) connStartBlocker.getReply().getMethod(); _serverProperties = connStart.getServerProperties(); Version serverVersion = new Version(connStart.getVersionMajor(), connStart.getVersionMinor()); if (!Version.checkVersion(clientVersion, serverVersion)) { _frameHandler.close(); //this will cause mainLoop to terminate throw new ProtocolVersionMismatchException(clientVersion, serverVersion); } } catch (ShutdownSignalException sse) { throw AMQChannel.wrap(sse); } String[] mechanisms = connStart.getMechanisms().toString().split(" "); SaslMechanism sm = _factory.getSaslConfig().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, _factory); AMQP.Connection.Tune connTune = null; do { Method method = (challenge == null) ? new AMQImpl.Connection.StartOk(_clientProperties, sm.getName(), response, "en_US") : new AMQImpl.Connection.SecureOk(response); 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, _factory); } } catch (ShutdownSignalException e) { throw new PossibleAuthenticationFailureException(e); } } while (connTune == null); int channelMax = negotiatedMaxValue(_factory.getRequestedChannelMax(), connTune.getChannelMax()); _channelManager = new ChannelManager(channelMax); int frameMax = negotiatedMaxValue(_factory.getRequestedFrameMax(), connTune.getFrameMax()); setFrameMax(frameMax); int heartbeat = negotiatedMaxValue(_factory.getRequestedHeartbeat(), connTune.getHeartbeat()); setHeartbeat(heartbeat); _channel0.transmit(new AMQImpl.Connection.TuneOk(channelMax, frameMax, heartbeat)); // 0.9.1: insist [on not being redirected] is deprecated, but // still in generated code; just pass a dummy value here _channel0.exnWrappingRpc(new AMQImpl.Connection.Open(_virtualHost, "", false)).getMethod(); return; }