8-TP JMS 8-3JMS Spring ActiveMQ Publish Subscriber
8-TP JMS 8-3JMS Spring ActiveMQ Publish Subscriber
2. Objectifs
1. Développement d’un producer JMS : @EnableJms, JmsTemplate
2. Configuration et Injecton de la configuration du topic avec spring boot :
ActiveMQConnectionFactory, JmsTemplate
3. Communication en mode publish/subscriber via une topic :
template.setPubSubDomain(true)
4. Développement d’un consumer JMS en mode asynchrone : @JmsListener
5. Publier/Consommer une liste d’objets Java « Campany » qui contient une liste de « Product »
à travers le Broker de type ActiveMQ(Artemis) externe
6. Console d’administration de Artemis (mode avancé)
3. Architecture
4. Installation de ActiveMQ/Artemis
1. Cf.TP2 de JMS
2. Développement d’un Publisher
jsa.activemq.broker.url=tcp://localhost:61616
jsa.activemq.borker.username=admin
jsa.activemq.borker.password=admin
jsa.activemq.topic=my-topic
spring.jms.pub-sub-domain=true
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
// name
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// products
public void setProducts(List<Product> products){
this.products = products;
}
public List<Product> getProducts(){
return this.products;
}
/**
*
* Show Detail View
*/
public String toString(){
JSONObject jsonInfo = new JSONObject();
try {
jsonInfo.put("name", this.name);
JSONArray productArray = new JSONArray();
if (this.products != null) {
this.products.forEach(product -> {
JSONObject subJson = new JSONObject();
try {
subJson.put("name",
product.getName());
} catch (JSONException e) {}
productArray.put(subJson);
});
}
jsonInfo.put("products", productArray);
} catch (JSONException e1) {}
return jsonInfo.toString();
}
}
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class,pr
operty="@id", scope = Product.class)
public class Product {
private String name;
public Product(){
}
public Product(String name){
this.name = name;
}
public Product(String name, Company company){
this.name = name;
this.company = company;
}
// name
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// products
public void setCompany(Company company){
this.company = company;
}
public Company getCompany(){
return this.company;
}
}
b. Classe de Configuration de la ConnectionFactory, topic…
package com.the.basic.tech.info.activemq.config;
import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.core.JmsTemplate;
import
org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
@Value("${jsa.activemq.borker.username}")
String userName;
@Value("${jsa.activemq.borker.password}")
String password;
/*
* Initial ConnectionFactory
*/
@Bean
public ConnectionFactory connectionFactory(){
ActiveMQConnectionFactory connectionFactory = new
ActiveMQConnectionFactory();
connectionFactory.setBrokerURL(brokerUrl);
connectionFactory.setUserName(userName);
connectionFactory.setPassword(password);
return connectionFactory;
}
@Bean
public JmsTemplate jmsTemplate(){
package com.the.basic.tech.info.activemq.jms;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import com.the.basic.tech.info.activemq.models.Company;
@Component
public class MyJmsPublisher {
private static final Logger logger =
LoggerFactory.getLogger(MyJmsPublisher.class);
//Default settings for JMS Sessions are "not transacted" and "auto-
acknowledge".As defined by the Java EE specification,
@Autowired
JmsTemplate jmsTemplate;
@Value("${jsa.activemq.topic}")
String topic;
package com.the.basic.tech.info.activemq;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplication;
import com.the.basic.tech.info.activemq.jms.MyJmsPublisher;
import com.the.basic.tech.info.activemq.models.Company;
import com.the.basic.tech.info.activemq.models.Product;
@SpringBootApplication
public class SpringActiveMqTopicProducerApplication implements
CommandLineRunner {
@Autowired
MyJmsPublisher publisher;
SpringApplication.run(SpringActiveMqTopicProducerApplication.
class, args);
}
@Override
public void run(String... args) throws Exception {
/*
* Apple company & products
*/
// initial company and products
Product iphone7 = new Product("Iphone X");
Product iPadPro = new Product("IPadPro");
/*
* Samsung company and products
*/
Product galaxySx = new Product("Galaxy SXX");
Product gearSy = new Product("Gear YYY");
List<Product> samsungProducts = new
ArrayList<Product>(Arrays.asList(galaxySx, gearSy));
/*
* send message to ActiveMQ
*/
publisher.send(samsung);
}
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.4)
Il est possible de visualiser les attributs des topics, des files d'attente et du broker
connecté en faisant un clic gauche sur chaque nœud.
Les Topics ont une couleur bleu, et les Queues ont une couleur verte.
3. Développement du Subscriber (Consumer de la topic en mode Asynchrone)
a. Créer le projet Maven « SpringActiveMqTopicConsumer »
a. Le fichier « pom.xml » :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.activemq</groupId>
<artifactId>SpringActiveMqTopicConsumer</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>SpringActiveMqTopicConsumer</name>
<description>SpringActiveMqTopicConsumer</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-
8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-
activemq</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build><plugins><plugin><groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build></project>
jsa.activemq.broker.url=tcp://localhost:61616
jsa.activemq.borker.username=admin
jsa.activemq.borker.password=admin
jsa.activemq.topic=my-topic
spring.jms.pub-sub-domain=true
c. La classe « Campany » et « Product » sont les mêmes que dans le Publisher
e. Classe « JmsSubcriber »
package com.the.basic.tech.info.activemq.jms;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import com.the.basic.tech.info.activemq.models.Company;
@Component
public class JmsSubcriber {
private static final Logger logger =
LoggerFactory.getLogger(JmsSubcriber.class);
@JmsListener(destination = "${jsa.activemq.topic}")
public void receive(Company msg){
logger.info("*** JmsSubcriber Recieved Message: {}",
msg.toString());
}
}
package com.the.basic.tech.info.activemq;
import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringActiveMqTopicConsumerApplication {
➔ Réexécuter le Producer
➔ Exécuter le Subscriber :
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.4)
Suite à l’exécution du Subscriber, une Queue a été crée et été attachée à la Topic
correspondante
Si on exécute le Scbscriber 3 fois par exemple, on obtient le diagramme ci-après :