Brief Analysis of ActeMQbroker Source Code

Keywords: PHP Jetty

Architecture diagram

The architecture of activeMQ is shown in the figure, leaving aside the right part, we can see that there are three parts from top to bottom:

1. connector: connector

2. region: mainly divided into topic and queue, dealing with related content separately

3. message store: storage

DEMO

Let's start with IDERunner, a test class for broker, and look at the broker source code, which is shown below

 1 // configuration management broker,connector
 2 BrokerService brokerService = new BrokerService();
 3 // To configure----------------------------------------------------------
 4 // Set up broker Bound address address
 5 String bindAddress = "tcp://0.0.0.0:61616?trace=" + TRANSPORT_TRACE + "&transport.wireFormat.maxFrameSize=104857600";
 6 // Add Connector
 7 // 1,Will be based on bindAddress Of schema structure connector Connector, build TransportServer(If it is Http,Then use Jetty Of connector Implement)
 8 brokerService.addConnector(bindAddress);
 9 // broker Whether to persist messages
10 // 1,true Indicates open persistence
11 brokerService.setPersistent(true);
12 // Whether to use jmx
13 brokerService.setUseJmx(false);
14 // Allow alert demotion
15 brokerService.setAdvisorySupport(false);
16 // start-up-----------------------------------------------------------
17 // start-up brokerService
18 brokerService.start();
19 // Waiting for End-------------------------------------------------------
20 // Main Thread await,Until brokerService Status is stop
21 brokerService.waitUntilStopped();

Example 8 lines of code with 21 lines of comments.

Source Parsing

addConnector

Line 2 builds the BrokerService object, and line 4 addConnector builds the connector, which creates the TransportConnector and adds it to the BrokerService.

1 public TransportConnector addConnector(URI bindAddress) throws Exception {
2   return addConnector(createTransportConnector(bindAddress));
3 }

Enter the createTransportConnector method and build TransportServer via Communism before constructing TransportConnector

1 protected TransportConnector createTransportConnector(URI brokerURI) throws Exception {
2     TransportServer transport = TransportFactorySupport.bind(this, brokerURI);
3     return new TransportConnector(transport);
4 }

Enter the bind method again, select TransportFactory, and call its doBind method to complete the creation of TransportServer.For example, HttpTransportServer is created by HttpTransportFactory.

 1 public static TransportServer bind(BrokerService brokerService, URI location) throws IOException {
 2     TransportFactory tf = TransportFactory.findTransportFactory(location); // according to schema find factory
 3     if( brokerService!=null && tf instanceof BrokerServiceAware) {
 4         ((BrokerServiceAware)tf).setBrokerService(brokerService);
 5     }
 6     try {
 7         if( brokerService!=null ) {
 8             SslContext.setCurrentSslContext(brokerService.getSslContext());
 9         }
10         return tf.doBind(location); // structure Transportserver
11     } finally {
12         SslContext.setCurrentSslContext(null);
13     }
14 }

In general, the addConnector method is to create a TransportConnector that contains TransportServer for handling communications (such as Http communications implemented by HttpTransportServer).

start

Looking at line 18 again, brokerService calls the start method, which enters the method, the core of which is to start the broker

startBroker(startAsync)
 1 private void startBroker(boolean async) throws Exception {
 2     if (async) {
 3         new Thread("Broker Starting Thread") {
 4             @Override
 5             public void run() {
 6                 // ...
 7                 doStartBroker();
 8                 // ...
 9             }
10         }.start();
11     } else {
12         doStartBroker();
13     }
14 }

Follow up on doStartBroker

1 // ...
2 broker = getBroker(); // Obtain broker Instance object
3 // ...
4 broker.start(); // start-up broker, region, destination
5 // ...
6 startAllConnectors(); // start-up connectors Connector
7 // ...

The second line of the getBroker method creates the Broker's implementation class RegionBroker, which contains region implementations such as QueueRegion and TopicRegion.

Line 4 start method starts broker and all region s

1 public void start() throws Exception {
2     started = true; // modify broker Status of
3     // start-up region,region All under destination Will also start
4     queueRegion.start(); // start-up queue region
5     topicRegion.start(); // start-up topic region
6     tempQueueRegion.start(); // start-up temp queue region
7     tempTopicRegion.start(); // start-up temp topic region
8     // ...
9 }

Next line 6, the startAllConnectors method starts all the TransportConnector s we created

1 // ...
2 for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
3     TransportConnector connector = iter.next();
4     al.add(startTransportConnector(connector)); // Start Connector
5 }
6 // ...

Enter the startTransportConnector method, which calls the Connector's start

1 public TransportConnector startTransportConnector(TransportConnector connector) throws Exception {
2     // ...
3     connector.start();
4     return connector;
5 }

start method to follow up TransportConnector

 1 public void start() throws Exception {
 2     broker = brokerService.getBroker();
 3     // ...
 4     // Add to transport Monitor
 5     // from jetty Connector callback current listener Of onAccept Method
 6     getServer().setAcceptListener(new TransportAcceptListener() {
 7         @Override
 8         public void onAccept(final Transport transport) {
 9             // ...
10             try {
11                 brokerService.getTaskRunnerFactory().execute(new Runnable() {
12                     @Override
13                     public void run() {
14                         try {
15                             if (!brokerService.isStopping()) {
16                                 // Receive Client transport Connect
17                                 Connection connection = createConnection(transport); // Establish transport Of connection
18                                 connection.start(); // Start the connection
19                             } else {
20                                 // ...
21                             }
22                         } catch (Exception e) {
23                             // ...
24                         }
25                     }
26                 });
27             } catch (Exception e) {
28                 // ...
29             }
30         }
31         // ...
32     });
33     getServer().setBrokerInfo(brokerInfo);
34     getServer().start(); // transport server
35     // ...
36 }

The core of the start method has two pieces

1. A Transport listener is set up, that is, if a client initiates a transport connection, the listener will be triggered.

2. Start TransportServer

Let's first see what TransportServer.doStart does (take HttpTransportServer for example)

 1 protected void doStart() throws Exception {
 2     createServer(); // Establish jetty Of server object
 3     // ...
 4     ServletHolder holder = new ServletHolder();
 5     holder.setServlet(new HttpTunnelServlet());
 6     contextHandler.addServlet(holder, "/"); // All Mapping Paths
 7     // ...
 8     server.start(); // start-up jetty Of server
 9     // ...
10 }

The main purpose is to use Jetty's server for HTTP services, where an HttpTunnelServlet is created to process requests.When a request comes in from the HttpTunnelServlet, it is wrapped as a Transport, which triggers the TransportServerListener we just mentioned in the first step and creates a Connection into the createConnection method

1 protected Connection createConnection(Transport transport) throws IOException {
2     //...
3     TransportConnection answer = new TransportConnection(this, transport, broker, disableAsyncDispatch ? null
4             : taskRunnerFactory, brokerService.getTaskRunnerFactory());
5     // ...
6     return answer;
7 }

Follow the TransportConnection construction method, which does two things

1. The service method handles command s, such as sending a Message that calls the broker's send, and the broker will find a corresponding region -> destination -> Message store -> addMessage to process

2. dispatchSync distributes messages

 1 public TransportConnection(TransportConnector connector, final Transport transport, Broker broker,
 2                            TaskRunnerFactory taskRunnerFactory, TaskRunnerFactory stopTaskRunnerFactory) {
 3     // ...
 4     this.transport.setTransportListener(new DefaultTransportListener() {
 5         @Override
 6         public void onCommand(Object o) {
 7             // ...
 8             try {
 9                 // ...
10                 Command command = (Command) o;
11                 if (!brokerService.isStopping()) {
12                     Response response = service(command);
13                     if (response != null && !brokerService.isStopping()) {
14                         // Received Message
15                         dispatchSync(response);
16                     }
17                 } else {
18                     // ...
19                 }
20             } finally {
21                 // ...
22             }
23         }
24         // ...
25     });
26     // ...
27 }

UML

Posted by DeltaRho2K on Wed, 03 Jul 2019 09:41:44 -0700