How to integrate a mqtt broker into spring boot project - spring

How to integrate a mqtt broker into spring boot project ?
I had ever tried spring-boot-starter-activemq , but it is a client ,not a broker
the main purpose is bridge message between cloud mqtt broker and Intranet Mqtt broker , include message bridging and topic management

Messaging Broker server is independent, so Spring boot not provide implementation of mqtt broker, only using messaging broker client with spring boot you can connect with your MQTT broker like Mosqitto/VerneMq/RabbitMq etc.
Based on your message broker you can pick directly pick broker specific client library or
you can use spring-integration-mqtt module
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
You can configure inbound or outbound implementation using spring integration module based on your requirement, it will give u flexibility so you can switch from one mqtt broker to another.
Inbond example:
#SpringBootApplication
public class MqttJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MqttJavaApplication.class)
.web(false)
.run(args);
}
#Bean
public IntegrationFlow mqttInbound() {
return IntegrationFlows.from(
new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883",
"testClient", "topic1", "topic2");)
.handle(m -> System.out.println(m.getPayload()))
.get();
}
}
Outbond example:
#SpringBootApplication
public class MqttJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MqttJavaApplication.class)
.web(false)
.run(args);
}
#Bean
public IntegrationFlow mqttOutboundFlow() {
return f -> f.handle(new MqttPahoMessageHandler("tcp://host1:1883", "someMqttClient"));
}
}
You can go through with spring boot integration-mqtt module docs for more details.

Related

Can a Spring Boot standalone application integrated with Camunda consume JMS messages from JbossFuse?

I have a activemq:queue inQueue in my JbossFuse. How do I consume those JMS messages which are enqueued so that my process instance is triggered in the Spring boot application integrated with Camunda ? Any link to references or samples would be helpful ?
Currently I am able to consume messages from activemq but I am not sure how to consume the messages from Jboss Fuse ActiveMQ ?
#Component
public class ActiveMQConsumer {
#Autowired
CamelContext camelContext;
#Autowired
ProducerTemplate producerTemplate;
#SuppressWarnings("unchecked")
#JmsListener(destination = "inQueue")
public void consumeMessage(JSONObject employeeRecord) throws Exception {
if (employeeRecord instanceof JSONObject) {
HashMap<String, Object> employeeRecordMap = (HashMap<String, Object>) employeeRecord.toMap();
Exchange exchange = ExchangeBuilder.anExchange(camelContext).withBody(employeeRecordMap).build();
HashMap<String, Object> employeeDetails = (HashMap<String, Object>) employeeRecordMap.get("employeeDetails");
exchange.setProperty("CamundaBpmBusinessKey", employeeDetails.get("employeeADId"));
producerTemplate.send("camunda-bpm:start?processDefinitionKey=camunda-camel-activeMQ", exchange);
}
}
}
application.properties
# activeMQ config
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
Expected to consume messages from JbossFuse.
I would recommend using the maven archetype io.fabric8.archetypes spring-boot-camel-amq-archetype version 2.2.197. This can be found:
Spring Boot example running a Camel route connecting to ActiveMQ
http://repo1.maven.org/maven2/
This will get you a nice sample project that has all of the Camel and Spring dependencies and some nice samples.

JMS with spring boot, sender and receiver on same package: what is its use?

I am learning JMS with spring boot and nice to know that spring boot comes with embed Active MQ JMS broker.
I started from spring page on how to achieve this and it works like charm. Now i went little further and create two separate spring boot application one containing jms sender code and another containing receiver code.
I tried starting and application failed as both application are using same port for JMS. I fixed this by including this on one application
#Bean
public BrokerService broker() throws Exception {
final BrokerService broker = new BrokerService();
broker.addConnector("tcp://localhost:61616");
broker.addConnector("vm://localhost");
broker.setPersistent(false);
return broker;
}
But now sender is sending message successfully but receiver is doing nothing. I search on stackoverflow and look at this and this. And they are saying:
If you want to use JMS in production, it would be much wiser to avoid using Spring Boot embedded JMS brokers and host it separately. So 3 node setup would be preferred for PROD.
So my questions are:
1. What is the purpose of putting both jms sender and receiver on same application? Is there any practical example
2. Is it really not possible to use spring boot embedded JMS to communicate two separate application.
You might have sender and receiver in the same application if requests arrive in bursts and you want to save them somewhere before they are processed, in case of a server crash. You typically still wouldn't use an embedded broker for that.
Embedded brokers are usually used for testing only.
You can, however, run an embedded broker that is accessible externally; simply fire up a BrokerService as you have, but the other app needs to connect with the tcp://... address, not the vm://....
EDIT
App1:
#SpringBootApplication
#RestController
public class So52654109Application {
public static void main(String[] args) {
SpringApplication.run(So52654109Application.class, args);
}
#Bean
public BrokerService broker() throws Exception {
final BrokerService broker = new BrokerService();
broker.addConnector("tcp://localhost:61616");
broker.setPersistent(false);
broker.start();
return broker;
}
#Autowired
private JmsTemplate template;
#RequestMapping(path = "/foo/{id}")
public String foo(#PathVariable String id) {
template.convertAndSend("someQueue", id);
return id + ": thank you for your request, we'll send an email to the address on file when complete";
}
}
App2:
application.properties
spring.activemq.broker-url=tcp://localhost:61616
and
#SpringBootApplication
public class So526541091Application {
public static void main(String[] args) {
SpringApplication.run(So526541091Application.class, args);
}
#JmsListener(destination = "someQueue")
public void process(String id) {
System.out.println("Processing request for id");
}
}
Clearly, for a simple app like this you might just run the listener in the first app.
However, since there is no persistence of messages with this configuration, you would likely use an external broker for a production app (or enable persistence).

Spring Cloud Stream topic per message for different consumers

The topology I am looking for is
So far I have not seen a way to define the topic per message in Cloud Stream. I understand that the consumers will be bound to specific topic but how does the producer sets the topic per message before sending the message to the exchange?
source.output().send(MessageBuilder.withPayload(myMessage).build());
Does not provide any way to set the topic for the exchange to route to the proper consumer.
Or maybe I don't understand something correctly?
UPDATE
I would expect not to receive the message in the consumer due to the bindingRoutingKey being 2222 and I am sending with routeTo 1111. But I still receive it on the consumer.
Producer Properties:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.cloud.stream.bindings.output.content-type=application/json
spring.cloud.stream.bindings.output.destination=messageExchange
spring.cloud.stream.rabbit.bindings.output.producer.routing-key-expression=headers['routeTo']
#EnableBinding(Source.class)
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Sender:
source.output().send(MessageBuilder.withPayload(mo).setHeader("routeTo", "1111").build());
And the Consumer:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.cloud.stream.bindings.input.destination=messageExchange
spring.cloud.stream.rabbit.bindings.input.consumer.bindingRoutingKey=2222
Application:
#SpringBootApplication
#EnableBinding(Sink.class)
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#StreamListener(Sink.INPUT)
public void ReceiveMo(String moDTO) {
log.info("Message received moDTO: {}", moDTO);
}
}
SECOND UPDATE
With the suggestions in the accepted answer below. I was able to make it work. Needed to remove the exchanges and queues from RabbitMQ using its UI and restart the RabbitMQ docker image.
The the routingKeyExpression rabbitmq producer property.
e.g. ...producer.routing-key-expression=headers['routeTo']
then
source.output().send(MessageBuilder.withPayload(myMessage)
.setHeader("routeTo", "Booking.new")
.build());
Note that the destination is the exchange name. By default, the binder expects a Topic exchange. If you wish to use a Direct exchange instead, you must set the exchangeType property.

Activemq web console in Spring

I am creating an embedded ActiveMQ broker in Spring application like this:
#EnableJms
#Configuration
public class MqConfig {
#Bean
public BrokerService broker() throws Exception {
BrokerService broker = new BrokerService();
broker.setBrokerName("ETL");
broker.addConnector("tcp://localhost:61616");
broker.start();
return broker;
}
}
How can I embed the ActiveMQ Admin Web console also in the same spring application? Searched the net for 2-3 hours, but found no useful answer. The only thing that ActiveMQ site mentions is this http://activemq.apache.org/web-console.html, however is not useful with Spring

How to expose Hystrix Stream on Spring Actuator port?

I am using Jetty embedded server in the Spring Boot application.
To handle requests I provide my custom handler like that.
#Slf4j
#Configuration
#EnableWebMvc
#SpringBootApplication
public class Main {
public static void main(String... args) {
new SpringApplicationBuilder().sources(Main.class).run(args);
}
#Bean
public EmbeddedServletContainerCustomizer customizer(JettyRequestHandler myCustomHandler) throws MalformedURLException {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof JettyEmbeddedServletContainerFactory) {
customizeJetty((JettyEmbeddedServletContainerFactory) container);
}
}
private void customizeJetty(JettyEmbeddedServletContainerFactory jetty) {
jetty.addServerCustomizers((JettyServerCustomizer) server -> {
HandlerCollection handlerCollection = new HandlerCollection();
handlerCollection.setHandlers(new Handler[]{myCustomHandler, server.getHandler()});
server.setHandler(handlerCollection);
});
}
};
}
}
I am listening for a requests on a standard 8080 port. I included also Spring Boot Actuator into my project to get some production endpoints (health, etc.). It starts on another port: 8181.
Additionally I am using Hystrix for circuit breaking purposes.
My question is how to enable Hystrix Stream to be exposed on actuator port?
Currently I managed only to expose it on standard port 8080 with following piece of code:
#Bean
public ServletRegistrationBean hystrixStreamServlet(){
return new ServletRegistrationBean(new HystrixMetricsStreamServlet(), "/hystrix.stream");
}
But I would like to expose it on another, to have the default one only for application purposes.
Those are some of my dependecies:
compile 'com.netflix.hystrix:hystrix-core:1.5.3'
compile 'com.netflix.hystrix:hystrix-metrics-event-stream:1.5.3'
compile 'org.springframework.boot:spring-boot-starter-actuator:1.3.5.RELEASE'
I would like NOT to use Spring Cloud where is #EnableHystrix that gives the stream on the actuator port actually.
Actually I did what #m-deinum proposed and it worked. I used Spring Cloud Stack.
To achieve Hystrix Stream on actuator I added dependecies:
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE' // spring cloud starter
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-hystrix', version: '1.1.3.RELEASE' // spring cloud hystrix starter
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-ribbon', version: '1.1.3.RELEASE' // spring ribbon starter
And the annotation on the Main class:
#EnableCircuitBreaker
#SpringBootApplication
public class Main {
public static void main(String... args) {
new SpringApplicationBuilder().sources(Main.class).run(args);
}
// ...
}

Resources