Messaging with HiveMQ MQTT Client
The HiveMQ MQTT Client is a Java library that enables applications to communicate using the MQTT (Message Queuing Telemetry Transport) protocol. It supports MQTT V3.x and MQTT V5.0 and provides multiple programming models, including blocking and asynchronous APIs. These programming models allow us to choose between simple synchronous execution and scalable non-blocking communication.
The library is widely used in IoT (Internet of Things) systems because MQTT is a lightweight publish-subscribe protocol that enables efficient message exchange between devices and servers through a broker. It provides features such as automatic reconnect, secure communication, and flexible message handling, which make it suitable for both small and enterprise systems.
This article focuses on the asynchronous model, which is commonly used in real-time applications such as IoT devices, event streaming systems, and messaging platforms.
1. Project Dependencies
<dependencies>
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-mqtt-client</artifactId>
<version>1.3.13</version>
</dependency>
</dependencies>
The above configuration includes the HiveMQ MQTT Client dependency.
2. Creating MQTT Clients
The asynchronous client is created using a builder provided by the HiveMQ library.
public class MqttService {
public static Mqtt5AsyncClient createClient(String clientId) {
return Mqtt5Client.builder()
.identifier(clientId)
.serverHost("broker.hivemq.com")
.serverPort(1883)
.buildAsync();
}
}
This method creates a reusable asynchronous MQTT client configured to connect to the public HiveMQ broker. The buildAsync() method ensures that all operations are non-blocking.
Creating a Blocking Client
public static Mqtt5BlockingClient createClient() {
return Mqtt5Client.builder()
.identifier("blocking-client")
.serverHost("broker.hivemq.com")
.serverPort(1883)
.buildBlocking();
}
This code creates a blocking MQTT client using the builder API. The client executes operations synchronously, meaning each operation waits for completion before the next begins.
Connecting to the Broker
The asynchronous client connects to the broker using a non-blocking operation that returns a completion stage.
Mqtt5AsyncClient client = MqttService.createClient("subscriber");
client.connect().join();
The connect method initiates a connection to the broker and can register a callback using whenComplete. The join() method ensures the client is fully connected before proceeding to subscribe or publish messages.
3. Subscribing to a Topic
This application listens for messages published to a specific MQTT topic. It connects to the broker, subscribes to a topic, and prints any incoming messages to the console in real time.
public class Subscriber {
void main() {
Mqtt5AsyncClient client = MqttService.createClient("subscriber");
client.connect().join();
IO.println("Subscriber connected");
client.subscribeWith()
.topicFilter("demo/topic")
.callback(publish -> {
String msg = new String(publish.getPayloadAsBytes(), StandardCharsets.UTF_8);
IO.println("Received: " + msg);
})
.send()
.join();
IO.println("Subscriber listening on demo/topic");
}
}
The Subscriber class creates an asynchronous MQTT client using a unique client identifier. It connects to the broker using connect().join() to ensure the connection is fully established before continuing. After connecting, it subscribes to the topic demo/topic.
The callback method is triggered whenever a message is received on that topic, converting the payload from bytes into a readable string and printing it to the console. The use of join() ensures that the subscription is successfully registered before the application continues running, making the subscriber ready to receive messages immediately.
4. Publishing Messages
This application sends messages to the same MQTT topic that the subscriber is listening to. Each message is published asynchronously and acknowledged by the broker.
public class Publisher {
void main() {
Mqtt5AsyncClient client = MqttService.createClient("publisher");
client.connect().join();
IO.println("Publisher connected");
publish(client, "Hello from Java Publisher");
publish(client, "Second message");
publish(client, "MQTT is working!");
client.disconnect().join();
IO.println("Publisher disconnected");
}
private static void publish(Mqtt5AsyncClient client, String message) {
client.publishWith()
.topic("demo/topic")
.payload(message.getBytes(StandardCharsets.UTF_8))
.qos(MqttQos.EXACTLY_ONCE)
.retain(true)
.send()
.join();
IO.println("Published: " + message);
}
}
The Publisher class creates an asynchronous MQTT client with a different client identifier to avoid conflicts with the subscriber. It connects to the broker and then publishes multiple messages to the demo/topic. Each message is converted into a byte array before being sent. The use of join() after send() ensures that each message is fully acknowledged by the broker before moving to the next one.
Finally, the client disconnects after all messages have been published, ensuring proper resource cleanup and preventing background threads from lingering.
Verification Flow
To see the MQTT communication:
Step 1: Start Subscriber – Terminal 1:
mvn compile exec:java -Dexec.mainClass="com.jcg.example.Subscriber"
Subscriber waits:
Subscriber connected Subscriber listening on demo/topic
Step 2: Start Publisher – Terminal 2:
mvn compile exec:java -Dexec.mainClass="com.jcg.example.Publisher"
Expected Publisher Output:
Publisher connected Published: Hello from Java Publisher Published: Second message Published: MQTT is working! Publisher disconnected
Step 3: Observe Subscriber Output – Back in Terminal 1:
Received: Hello from Java Publisher Received: Second message Received: MQTT is working!
- Both apps connect to the same broker:
broker.hivemq.com - Publisher sends messages to
demo/topic - Broker routes messages to all subscribers of that topic
- Subscriber receives messages instantly via callback
- Client IDs must be unique
- Subscriber must start first. Otherwise messages may be missed.
- Keep subscriber running. It is event driven and does not exit automatically.
5. Conclusion
In this article, a messaging system was built using the HiveMQ MQTT Client in Java. The implementation demonstrated how to create publisher and subscriber applications, connect them to a shared MQTT broker, and exchange messages through a common topic.
6. Download the Source Code
This article provided an introduction to the HiveMQ MQTT Client.
You can download the full source code of this example here: hivemq mqtt client

