JAVA-15787 Created new messaging-modules and saas-modules
- Moved jgroups, rabbitmq, spring-amqp, spring-apache-camel, spring-jms to messaging-modules - Moved twilio, twitter4j, strip to saas-modules - Renamed existing saas to jira-rest-integration
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
## Reliable Messaging with JGroups Tutorial Project
|
||||
|
||||
This module contains articles about JGroups.
|
||||
|
||||
### Relevant Article:
|
||||
- [Reliable Messaging with JGroups](https://www.baeldung.com/jgroups)
|
||||
|
||||
### Overview
|
||||
This Maven project contains the Java code for the article linked above.
|
||||
|
||||
### Package Organization
|
||||
Java classes for the intro tutorial are in the org.baeldung.jgroups package.
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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>
|
||||
<artifactId>jgroups</artifactId>
|
||||
<name>jgroups</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Reliable Messaging with JGroups Tutorial</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>messaging-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jgroups</groupId>
|
||||
<artifactId>jgroups</artifactId>
|
||||
<version>${jgroups.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>${commons-cli.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<jgroups.version>4.0.10.Final</jgroups.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,212 @@
|
||||
package com.baeldung.jgroups;
|
||||
|
||||
import org.apache.commons.cli.*;
|
||||
import org.jgroups.*;
|
||||
import org.jgroups.util.Util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class JGroupsMessenger extends ReceiverAdapter {
|
||||
|
||||
private JChannel channel;
|
||||
private String userName;
|
||||
private String clusterName;
|
||||
private View lastView;
|
||||
private boolean running = true;
|
||||
|
||||
// Our shared state
|
||||
private Integer messageCount = 0;
|
||||
|
||||
/**
|
||||
* Connect to a JGroups cluster using command line options
|
||||
* @param args command line arguments
|
||||
* @throws Exception
|
||||
*/
|
||||
private void start(String[] args) throws Exception {
|
||||
processCommandline(args);
|
||||
|
||||
// Create the channel
|
||||
// This file could be moved, or made a command line option.
|
||||
channel = new JChannel("src/main/resources/udp.xml");
|
||||
|
||||
// Set a name
|
||||
channel.name(userName);
|
||||
|
||||
// Register for callbacks
|
||||
channel.setReceiver(this);
|
||||
|
||||
// Ignore our messages
|
||||
channel.setDiscardOwnMessages(true);
|
||||
|
||||
// Connect
|
||||
channel.connect(clusterName);
|
||||
|
||||
// Start state transfer
|
||||
channel.getState(null, 0);
|
||||
|
||||
// Do the things
|
||||
processInput();
|
||||
|
||||
// Clean up
|
||||
channel.close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick and dirty implementaton of commons cli for command line args
|
||||
* @param args the command line args
|
||||
* @throws ParseException
|
||||
*/
|
||||
private void processCommandline(String[] args) throws ParseException {
|
||||
|
||||
// Options, parser, friendly help
|
||||
Options options = new Options();
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
|
||||
options.addOption("u", "user", true, "User name")
|
||||
.addOption("c", "cluster", true, "Cluster name");
|
||||
|
||||
CommandLine line = parser.parse(options, args);
|
||||
|
||||
if (line.hasOption("user")) {
|
||||
userName = line.getOptionValue("user");
|
||||
} else {
|
||||
formatter.printHelp("JGroupsMessenger: need a user name.\n", options);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
if (line.hasOption("cluster")) {
|
||||
clusterName = line.getOptionValue("cluster");
|
||||
} else {
|
||||
formatter.printHelp("JGroupsMessenger: need a cluster name.\n", options);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// Start it up
|
||||
public static void main(String[] args) throws Exception {
|
||||
new JGroupsMessenger().start(args);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void viewAccepted(View newView) {
|
||||
|
||||
// Save view if this is the first
|
||||
if (lastView == null) {
|
||||
System.out.println("Received initial view:");
|
||||
newView.forEach(System.out::println);
|
||||
} else {
|
||||
// Compare to last view
|
||||
System.out.println("Received new view.");
|
||||
|
||||
List<Address> newMembers = View.newMembers(lastView, newView);
|
||||
System.out.println("New members: ");
|
||||
newMembers.forEach(System.out::println);
|
||||
|
||||
List<Address> exMembers = View.leftMembers(lastView, newView);
|
||||
System.out.println("Exited members:");
|
||||
exMembers.forEach(System.out::println);
|
||||
}
|
||||
lastView = newView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop on console input until we see 'x' to exit
|
||||
*/
|
||||
private void processInput() throws Exception {
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||
while (running) {
|
||||
try {
|
||||
|
||||
// Get a destination, <enter> means broadcast
|
||||
Address destination = null;
|
||||
System.out.print("Enter a destination: ");
|
||||
System.out.flush();
|
||||
String destinationName = in.readLine().toLowerCase();
|
||||
|
||||
if (destinationName.equals("x")) {
|
||||
running = false;
|
||||
continue;
|
||||
} else if (!destinationName.isEmpty()) {
|
||||
destination = getAddress(destinationName)
|
||||
. orElseThrow(() -> new Exception("Destination not found"));
|
||||
}
|
||||
|
||||
// Accept a string to send
|
||||
System.out.print("Enter a message: ");
|
||||
System.out.flush();
|
||||
String line = in.readLine().toLowerCase();
|
||||
sendMessage(destination, line);
|
||||
} catch (IOException ioe) {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
System.out.println("Exiting.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message from here
|
||||
* @param destination the destination
|
||||
* @param messageString the message
|
||||
*/
|
||||
private void sendMessage(Address destination, String messageString) {
|
||||
try {
|
||||
System.out.println("Sending " + messageString + " to " + destination);
|
||||
Message message = new Message(destination, messageString);
|
||||
channel.send(message);
|
||||
} catch (Exception exception) {
|
||||
System.err.println("Exception sending message: " + exception.getMessage());
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(Message message) {
|
||||
// Print source and dest with message
|
||||
String line = "Message received from: " + message.getSrc() + " to: " + message.getDest() + " -> " + message.getObject();
|
||||
|
||||
// Only track the count of broadcast messages
|
||||
// Tracking direct message would make for a pointless state
|
||||
if (message.getDest() == null) {
|
||||
messageCount++;
|
||||
System.out.println("Message count: " + messageCount);
|
||||
}
|
||||
|
||||
System.out.println(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getState(OutputStream output) throws Exception {
|
||||
// Serialize into the stream
|
||||
Util.objectToStream(messageCount, new DataOutputStream(output));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(InputStream input) {
|
||||
|
||||
// NOTE: since we know that incrementing the count and transferring the state
|
||||
// is done inside the JChannel's thread, we don't have to worry about synchronizing
|
||||
// messageCount. For production code it should be synchronized!
|
||||
try {
|
||||
// Deserialize
|
||||
messageCount = Util.objectFromStream(new DataInputStream(input));
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error deserialing state!");
|
||||
}
|
||||
System.out.println(messageCount + " is the current messagecount.");
|
||||
}
|
||||
|
||||
|
||||
private Optional<Address> getAddress(String name) {
|
||||
View view = channel.view();
|
||||
return view.getMembers().stream().filter(address -> name.equals(address.toString())).findFirst();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,48 @@
|
||||
<config xmlns="urn:org:jgroups"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd">
|
||||
<UDP
|
||||
mcast_port="${jgroups.udp.mcast_port:45588}"
|
||||
ip_ttl="4"
|
||||
tos="8"
|
||||
ucast_recv_buf_size="5M"
|
||||
ucast_send_buf_size="5M"
|
||||
mcast_recv_buf_size="5M"
|
||||
mcast_send_buf_size="5M"
|
||||
max_bundle_size="64K"
|
||||
enable_diagnostics="true"
|
||||
thread_naming_pattern="cl"
|
||||
|
||||
thread_pool.min_threads="0"
|
||||
thread_pool.max_threads="20"
|
||||
thread_pool.keep_alive_time="30000"/>
|
||||
|
||||
<PING />
|
||||
<MERGE3 max_interval="30000"
|
||||
min_interval="10000"/>
|
||||
<FD_SOCK/>
|
||||
<FD_ALL/>
|
||||
<VERIFY_SUSPECT timeout="1500" />
|
||||
<BARRIER />
|
||||
<pbcast.NAKACK2 xmit_interval="500"
|
||||
xmit_table_num_rows="100"
|
||||
xmit_table_msgs_per_row="2000"
|
||||
xmit_table_max_compaction_time="30000"
|
||||
use_mcast_xmit="false"
|
||||
discard_delivered_msgs="true"/>
|
||||
<UNICAST3 xmit_interval="500"
|
||||
xmit_table_num_rows="100"
|
||||
xmit_table_msgs_per_row="2000"
|
||||
xmit_table_max_compaction_time="60000"
|
||||
conn_expiry_timeout="0"/>
|
||||
<pbcast.STABLE desired_avg_gossip="50000"
|
||||
max_bytes="4M"/>
|
||||
<pbcast.GMS print_local_addr="true" join_timeout="2000"/>
|
||||
<UFC max_credits="2M"
|
||||
min_threshold="0.4"/>
|
||||
<MFC max_credits="2M"
|
||||
min_threshold="0.4"/>
|
||||
<FRAG2 frag_size="60K" />
|
||||
<RSVP resend_interval="2000" timeout="10000"/>
|
||||
<pbcast.STATE_TRANSFER />
|
||||
</config>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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>
|
||||
<artifactId>messaging-modules</artifactId>
|
||||
<name>messaging-modules</name>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
<module>jgroups</module>
|
||||
<module>rabbitmq</module>
|
||||
<module>spring-amqp</module>
|
||||
<module>spring-apache-camel</module>
|
||||
<module>spring-jms</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
## RabbitMQ
|
||||
|
||||
This module contains articles about RabbitMQ.
|
||||
|
||||
### Relevant articles
|
||||
- [Introduction to RabbitMQ](https://www.baeldung.com/rabbitmq)
|
||||
- [Exchanges, Queues, and Bindings in RabbitMQ](https://www.baeldung.com/java-rabbitmq-exchanges-queues-bindings)
|
||||
- [Pub-Sub vs. Message Queues](https://www.baeldung.com/pub-sub-vs-message-queues)
|
||||
- [Channels and Connections in RabbitMQ](https://www.baeldung.com/java-rabbitmq-channels-connections)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
version: '3.0'
|
||||
services:
|
||||
rabbitmq:
|
||||
image: rabbitmq:3-management
|
||||
environment:
|
||||
- RABBITMQ_DEFAULT_USER=guest
|
||||
- RABBITMQ_DEFAULT_PASS=guest
|
||||
- RABBITMQ_VM_MEMORY_HIGH_WATERMARK_RELATIVE=0.8
|
||||
ports:
|
||||
- "5672:5672"
|
||||
- "15672:15672"
|
||||
volumes:
|
||||
- ./src/rabbitmq/20-mem.conf:/etc/rabbitmq/conf.d/20-mem.conf
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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>
|
||||
<artifactId>rabbitmq</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<name>rabbitmq</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>messaging-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud-dependencies.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.rabbitmq</groupId>
|
||||
<artifactId>amqp-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-dependencies.version>2020.0.3</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.baeldung.benchmark;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.baeldung.benchmark.Worker.WorkerResult;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
public class ConnectionPerChannelPublisher implements Callable<Long> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ConnectionPerChannelPublisher.class);
|
||||
private final ConnectionFactory factory;
|
||||
private final int workerCount;
|
||||
private final int iterations;
|
||||
private final int payloadSize;
|
||||
|
||||
ConnectionPerChannelPublisher(ConnectionFactory factory, int workerCount, int iterations, int payloadSize) {
|
||||
this.factory = factory;
|
||||
this.workerCount = workerCount;
|
||||
this.iterations = iterations;
|
||||
this.payloadSize = payloadSize;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
if (args.length != 4) {
|
||||
System.err.println("Usage: java " + ConnectionPerChannelPublisher.class.getName() + " <host> <#channels> <#messages> <payloadSize>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
ConnectionFactory factory = new ConnectionFactory();
|
||||
factory.setHost(args[0]);
|
||||
|
||||
int workerCount = Integer.parseInt(args[1]);
|
||||
int iterations = Integer.parseInt(args[2]);
|
||||
int payloadSize = Integer.parseInt(args[3]);
|
||||
|
||||
// run the benchmark 10x and get the average throughput
|
||||
LongSummaryStatistics summary = IntStream.range(0, 9)
|
||||
.mapToObj(idx -> new ConnectionPerChannelPublisher(factory, workerCount, iterations, payloadSize))
|
||||
.map(p -> p.call())
|
||||
.collect(Collectors.summarizingLong((l) -> l));
|
||||
|
||||
log.info("[I66] workers={}, throughput={}", workerCount, (int)Math.floor(summary.getAverage()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long call() {
|
||||
try {
|
||||
List<Worker> workers = new ArrayList<>();
|
||||
CountDownLatch counter = new CountDownLatch(workerCount);
|
||||
|
||||
for (int i = 0; i < workerCount; i++) {
|
||||
Connection conn = factory.newConnection();
|
||||
workers.add(new Worker("queue_" + i, conn, iterations, counter, payloadSize));
|
||||
}
|
||||
|
||||
ExecutorService executor = new ThreadPoolExecutor(workerCount, workerCount, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(workerCount, true));
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("[I61] Starting {} workers...", workers.size());
|
||||
executor.invokeAll(workers);
|
||||
if (counter.await(5, TimeUnit.MINUTES)) {
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
log.info("[I59] Tasks completed: #workers={}, #iterations={}, elapsed={}ms, stats={}", workerCount, iterations, elapsed);
|
||||
return throughput(workerCount, iterations, elapsed);
|
||||
} else {
|
||||
throw new RuntimeException("[E61] Timeout waiting workers to complete");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static long throughput(int workerCount, int iterations, long elapsed) {
|
||||
return (iterations * workerCount * 1000) / elapsed;
|
||||
}
|
||||
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
package com.baeldung.benchmark;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
public class SharedConnectionPublisher {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SharedConnectionPublisher.class);
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
try {
|
||||
|
||||
if ( args.length != 6) {
|
||||
System.err.println("Usage: java " + SharedConnectionPublisher.class.getName() + " <host> <#channels> <#messages> <payloadSize> <#channels/connection> <extra work time(ms)>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
ConnectionFactory factory = new ConnectionFactory();
|
||||
factory.setHost(args[0]);
|
||||
|
||||
List<Worker> workers = new ArrayList<>();
|
||||
|
||||
int workerCount = Integer.parseInt(args[1]);
|
||||
int iterations = Integer.parseInt(args[2]);
|
||||
int payloadSize = Integer.parseInt(args[3]);
|
||||
int channelsPerConnection = Integer.parseInt(args[4]);
|
||||
long extraWork = Long.parseLong(args[5]);
|
||||
|
||||
log.info("[I35] Creating {} worker{}...", workerCount, (workerCount > 1)?"s":"");
|
||||
|
||||
CountDownLatch counter = new CountDownLatch(workerCount);
|
||||
|
||||
int connCount = (workerCount + channelsPerConnection-1)/channelsPerConnection;
|
||||
List<Connection> connections = new ArrayList<>(connCount);
|
||||
for( int i =0 ; i< connCount; i++) {
|
||||
log.info("[I59] Creating connection#{}", i);
|
||||
connections.add(factory.newConnection());
|
||||
}
|
||||
|
||||
for( int i = 0 ; i < workerCount ; i++ ) {
|
||||
workers.add(new Worker("queue_" + i, connections.get(i % connCount), iterations, counter,payloadSize,extraWork));
|
||||
}
|
||||
|
||||
ExecutorService executor = new ThreadPoolExecutor(workerCount, workerCount, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(workerCount, true));
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("[I61] Starting workers...");
|
||||
List<Future<WorkerResult>> results = executor.invokeAll(workers);
|
||||
|
||||
log.info("[I55] Waiting workers to complete...");
|
||||
if( counter.await(5, TimeUnit.MINUTES) ) {
|
||||
long elapsed = System.currentTimeMillis() - start - (workerCount*iterations*extraWork);
|
||||
log.info("[I59] Tasks completed: #workers={}, #iterations={}, elapsed={}ms",
|
||||
workerCount,
|
||||
iterations,
|
||||
elapsed);
|
||||
|
||||
LongSummaryStatistics summary = results.stream()
|
||||
.map(f -> safeGet(f))
|
||||
.map(r -> r.elapsed)
|
||||
.collect(Collectors.summarizingLong((l) -> l));
|
||||
|
||||
log.info("[I74] stats={}", summary);
|
||||
log.info("[I79] result: workers={}, throughput={}",workerCount,throughput(workerCount,iterations,elapsed));
|
||||
|
||||
}
|
||||
else {
|
||||
log.error("[E61] Timeout waiting workers to complete");
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static long throughput(int workerCount, int iterations, long elapsed) {
|
||||
return (iterations*workerCount*1000)/elapsed;
|
||||
}
|
||||
|
||||
|
||||
private static <T> T safeGet(Future<T> f) {
|
||||
try {
|
||||
return f.get();
|
||||
}
|
||||
catch(Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static class WorkerResult {
|
||||
public final long elapsed;
|
||||
WorkerResult(long elapsed) {
|
||||
this.elapsed = elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class Worker implements Callable<WorkerResult> {
|
||||
|
||||
private final Connection conn;
|
||||
private final Channel channel;
|
||||
private int iterations;
|
||||
private final CountDownLatch counter;
|
||||
private final String queue;
|
||||
private final byte[] payload;
|
||||
private long extraWork;
|
||||
|
||||
Worker(String queue, Connection conn, int iterations, CountDownLatch counter,int payloadSize,long extraWork) throws IOException {
|
||||
this.conn = conn;
|
||||
this.iterations = iterations;
|
||||
this.counter = counter;
|
||||
this.queue = queue;
|
||||
this.extraWork = extraWork;
|
||||
|
||||
channel = conn.createChannel();
|
||||
channel.queueDeclare(queue, false, false, true, null);
|
||||
|
||||
this.payload = new byte[payloadSize];
|
||||
new Random().nextBytes(payload);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkerResult call() throws Exception {
|
||||
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
for ( int i = 0 ; i < iterations ; i++ ) {
|
||||
channel.basicPublish("", queue, null,payload);
|
||||
Thread.sleep(extraWork);
|
||||
}
|
||||
|
||||
long elapsed = System.currentTimeMillis() - start - (extraWork*iterations);
|
||||
channel.queueDelete(queue);
|
||||
return new WorkerResult(elapsed);
|
||||
}
|
||||
finally {
|
||||
counter.countDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.baeldung.benchmark;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.baeldung.benchmark.Worker.WorkerResult;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
public class SingleConnectionPublisher implements Callable<Long> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SingleConnectionPublisher.class);
|
||||
|
||||
private final ConnectionFactory factory;
|
||||
private final int workerCount;
|
||||
private final int iterations;
|
||||
private final int payloadSize;
|
||||
|
||||
SingleConnectionPublisher(ConnectionFactory factory, int workerCount, int iterations, int payloadSize) {
|
||||
this.factory = factory;
|
||||
this.workerCount = workerCount;
|
||||
this.iterations = iterations;
|
||||
this.payloadSize = payloadSize;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
if ( args.length != 4) {
|
||||
System.err.println("Usage: java " + SingleConnectionPublisher.class.getName() + " <host> <#channels> <#messages> <payloadSize>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
ConnectionFactory factory = new ConnectionFactory();
|
||||
factory.setHost(args[0]);
|
||||
|
||||
int workerCount = Integer.parseInt(args[1]);
|
||||
int iterations = Integer.parseInt(args[2]);
|
||||
int payloadSize = Integer.parseInt(args[3]);
|
||||
|
||||
LongSummaryStatistics summary = IntStream.range(0, 9)
|
||||
.mapToObj(idx -> new SingleConnectionPublisher(factory, workerCount, iterations, payloadSize))
|
||||
.map(p -> p.call())
|
||||
.collect(Collectors.summarizingLong((l) -> l));
|
||||
|
||||
log.info("[I66] workers={}, throughput={}", workerCount, (int)Math.floor(summary.getAverage()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long call() {
|
||||
|
||||
try {
|
||||
|
||||
Connection connection = factory.newConnection();
|
||||
CountDownLatch counter = new CountDownLatch(workerCount);
|
||||
List<Worker> workers = new ArrayList<>();
|
||||
|
||||
for( int i = 0 ; i < workerCount ; i++ ) {
|
||||
workers.add(new Worker("queue_" + i, connection, iterations, counter,payloadSize));
|
||||
}
|
||||
|
||||
ExecutorService executor = new ThreadPoolExecutor(workerCount, workerCount, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(workerCount, true));
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("[I61] Starting {} workers...", workers.size());
|
||||
List<Future<WorkerResult>> results = executor.invokeAll(workers);
|
||||
|
||||
if( counter.await(5, TimeUnit.MINUTES) ) {
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
|
||||
LongSummaryStatistics summary = results.stream()
|
||||
.map(f -> safeGet(f))
|
||||
.map(r -> r.elapsed)
|
||||
.collect(Collectors.summarizingLong((l) -> l));
|
||||
|
||||
log.info("[I59] Tasks completed: #workers={}, #iterations={}, elapsed={}ms, stats={}",
|
||||
workerCount,
|
||||
iterations,
|
||||
elapsed, summary);
|
||||
|
||||
return throughput(workerCount,iterations,elapsed);
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("[E61] Timeout waiting workers to complete");
|
||||
}
|
||||
}
|
||||
catch(Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T safeGet(Future<T> f) {
|
||||
try {
|
||||
return f.get();
|
||||
}
|
||||
catch(Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static long throughput(int workerCount, int iterations, long elapsed) {
|
||||
return (iterations*workerCount*1000)/elapsed;
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package com.baeldung.benchmark;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
public class SingleConnectionPublisherNio {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SingleConnectionPublisherNio.class);
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
try {
|
||||
|
||||
if ( args.length != 4) {
|
||||
System.err.println("Usage: java " + SingleConnectionPublisherNio.class.getName() + " <host> <#channels> <#messages> <payloadSize>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
ConnectionFactory factory = new ConnectionFactory();
|
||||
factory.setHost(args[0]);
|
||||
factory.useNio();
|
||||
Connection connection = factory.newConnection();
|
||||
|
||||
List<Worker> workers = new ArrayList<>();
|
||||
|
||||
int workerCount = Integer.parseInt(args[1]);
|
||||
int iterations = Integer.parseInt(args[2]);
|
||||
int payloadSize = Integer.parseInt(args[3]);
|
||||
|
||||
log.info("[I35] Creating {} worker{}...", workerCount, (workerCount > 1)?"s":"");
|
||||
|
||||
CountDownLatch counter = new CountDownLatch(workerCount);
|
||||
|
||||
for( int i = 0 ; i < workerCount ; i++ ) {
|
||||
workers.add(new Worker("queue_" + i, connection, iterations, counter,payloadSize));
|
||||
}
|
||||
|
||||
ExecutorService executor = new ThreadPoolExecutor(workerCount, workerCount, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(workerCount, true));
|
||||
long start = System.currentTimeMillis();
|
||||
log.info("[I61] Starting workers...");
|
||||
List<Future<WorkerResult>> results = executor.invokeAll(workers);
|
||||
|
||||
log.info("[I55] Waiting workers to complete...");
|
||||
if( counter.await(5, TimeUnit.MINUTES) ) {
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
log.info("[I59] Tasks completed: #workers={}, #iterations={}, elapsed={}ms",
|
||||
workerCount,
|
||||
iterations,
|
||||
elapsed);
|
||||
|
||||
LongSummaryStatistics summary = results.stream()
|
||||
.map(f -> safeGet(f))
|
||||
.map(r -> r.elapsed)
|
||||
.collect(Collectors.summarizingLong((l) -> l));
|
||||
|
||||
log.info("[I74] stats={}", summary);
|
||||
|
||||
}
|
||||
else {
|
||||
log.error("[E61] Timeout waiting workers to complete");
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static <T> T safeGet(Future<T> f) {
|
||||
try {
|
||||
return f.get();
|
||||
}
|
||||
catch(Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static class WorkerResult {
|
||||
public final long elapsed;
|
||||
WorkerResult(long elapsed) {
|
||||
this.elapsed = elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class Worker implements Callable<WorkerResult> {
|
||||
|
||||
private final Connection conn;
|
||||
private final Channel channel;
|
||||
private int iterations;
|
||||
private final CountDownLatch counter;
|
||||
private final String queue;
|
||||
private final byte[] payload;
|
||||
|
||||
Worker(String queue, Connection conn, int iterations, CountDownLatch counter,int payloadSize) throws IOException {
|
||||
this.conn = conn;
|
||||
this.iterations = iterations;
|
||||
this.counter = counter;
|
||||
this.queue = queue;
|
||||
|
||||
channel = conn.createChannel();
|
||||
channel.queueDeclare(queue, false, false, true, null);
|
||||
|
||||
this.payload = new byte[payloadSize];
|
||||
new Random().nextBytes(payload);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkerResult call() throws Exception {
|
||||
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
for ( int i = 0 ; i < iterations ; i++ ) {
|
||||
channel.basicPublish("", queue, null,payload);
|
||||
}
|
||||
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
channel.queueDelete(queue);
|
||||
return new WorkerResult(elapsed);
|
||||
}
|
||||
finally {
|
||||
counter.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.baeldung.benchmark;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
|
||||
public class Worker implements Callable<Worker.WorkerResult> {
|
||||
|
||||
private final Channel channel;
|
||||
private int iterations;
|
||||
private final CountDownLatch counter;
|
||||
private final String queue;
|
||||
private final byte[] payload;
|
||||
|
||||
Worker(String queue, Connection conn, int iterations, CountDownLatch counter, int payloadSize) throws IOException {
|
||||
this.iterations = iterations;
|
||||
this.counter = counter;
|
||||
this.queue = queue;
|
||||
|
||||
channel = conn.createChannel();
|
||||
channel.queueDelete(queue);
|
||||
channel.queueDeclare(queue, false, false, true, null);
|
||||
|
||||
this.payload = new byte[payloadSize];
|
||||
new Random().nextBytes(payload);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkerResult call() throws Exception {
|
||||
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
channel.basicPublish("", queue, null, payload);
|
||||
}
|
||||
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
channel.queueDelete(queue);
|
||||
return new WorkerResult(elapsed);
|
||||
} finally {
|
||||
counter.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class WorkerResult {
|
||||
public final long elapsed;
|
||||
|
||||
WorkerResult(long elapsed) {
|
||||
this.elapsed = elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.consumer;
|
||||
|
||||
import com.rabbitmq.client.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class Receiver {
|
||||
|
||||
private static final String QUEUE_NAME = "products_queue";
|
||||
|
||||
public static void main (String[] args) throws IOException, TimeoutException {
|
||||
ConnectionFactory factory = new ConnectionFactory();
|
||||
factory.setHost("localhost");
|
||||
Connection connection = factory.newConnection();
|
||||
Channel channel = connection.createChannel();
|
||||
|
||||
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
|
||||
|
||||
DefaultConsumer consumer = new DefaultConsumer(channel) {
|
||||
@Override
|
||||
public void handleDelivery(String consumerTag,
|
||||
Envelope envelope, AMQP.BasicProperties properties,
|
||||
byte[] body) throws IOException {
|
||||
String message = new String(body, "UTF-8");
|
||||
System.out.println(" [x] Received '" + message + "'");
|
||||
}
|
||||
};
|
||||
channel.basicConsume(QUEUE_NAME, true, consumer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.baeldung.producer;
|
||||
|
||||
import com.rabbitmq.client.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class Publisher {
|
||||
|
||||
private final static String QUEUE_NAME = "products_queue";
|
||||
|
||||
public static void main(String[]args) throws IOException, TimeoutException {
|
||||
ConnectionFactory factory = new ConnectionFactory();
|
||||
factory.setHost("localhost");
|
||||
Connection connection = factory.newConnection();
|
||||
Channel channel = connection.createChannel();
|
||||
|
||||
String message = "product details";
|
||||
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
|
||||
|
||||
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
|
||||
System.out.println(" [x] Sent '" + message + "'");
|
||||
|
||||
channel.close();
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.pubsubmq.client;
|
||||
|
||||
import org.springframework.amqp.core.Queue;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
public class ClientApplication {
|
||||
private static final String MESSAGE_QUEUE = "pizza-message-queue";
|
||||
|
||||
@Bean
|
||||
public Queue queue() {
|
||||
return new Queue(MESSAGE_QUEUE);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
|
||||
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.setQueueNames(MESSAGE_QUEUE);
|
||||
container.setMessageListener(listenerAdapter);
|
||||
return container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Consumer consumer() {
|
||||
return new Consumer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageListenerAdapter listenerAdapter(Consumer consumer) {
|
||||
return new MessageListenerAdapter(consumer, "receiveOrder");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ClientApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.pubsubmq.client;
|
||||
|
||||
public class Consumer {
|
||||
public void receiveOrder(String message) {
|
||||
System.out.printf("Order received: %s%n", message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.baeldung.pubsubmq.server;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
public class Publisher {
|
||||
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
private String queue;
|
||||
private String topic;
|
||||
|
||||
public Publisher(RabbitTemplate rabbitTemplate, String queue, String topic) {
|
||||
this.rabbitTemplate = rabbitTemplate;
|
||||
this.queue = queue;
|
||||
this.topic = topic;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postMessages() {
|
||||
rabbitTemplate.convertAndSend(queue, "1 Pepperoni");
|
||||
rabbitTemplate.convertAndSend(queue, "3 Margarita");
|
||||
rabbitTemplate.convertAndSend(queue, "1 Ham and Pineapple (yuck)");
|
||||
|
||||
rabbitTemplate.convertAndSend(topic, "notification", "New Deal on T-Shirts: 95% off!");
|
||||
rabbitTemplate.convertAndSend(topic, "notification", "2 for 1 on all Jeans!");
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.baeldung.pubsubmq.server;
|
||||
|
||||
import org.springframework.amqp.core.Binding;
|
||||
import org.springframework.amqp.core.BindingBuilder;
|
||||
import org.springframework.amqp.core.Queue;
|
||||
import org.springframework.amqp.core.TopicExchange;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class ServerApplication {
|
||||
private static final String MESSAGE_QUEUE = "pizza-message-queue";
|
||||
private static final String PUB_SUB_TOPIC = "notification-topic";
|
||||
private static final String PUB_SUB_EMAIL_QUEUE = "email-queue";
|
||||
private static final String PUB_SUB_TEXT_QUEUE = "text-queue";
|
||||
|
||||
@Bean
|
||||
public Queue queue() {
|
||||
return new Queue(MESSAGE_QUEUE);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue emailQueue() {
|
||||
return new Queue(PUB_SUB_EMAIL_QUEUE);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue textQueue() {
|
||||
return new Queue(PUB_SUB_TEXT_QUEUE);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TopicExchange exchange() {
|
||||
return new TopicExchange(PUB_SUB_TOPIC);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Binding emailBinding(Queue emailQueue, TopicExchange exchange) {
|
||||
return BindingBuilder.bind(emailQueue).to(exchange).with("notification");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Binding textBinding(Queue textQueue, TopicExchange exchange) {
|
||||
return BindingBuilder.bind(textQueue).to(exchange).with("notification");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Publisher publisher(RabbitTemplate rabbitTemplate) {
|
||||
return new Publisher(rabbitTemplate, MESSAGE_QUEUE, PUB_SUB_TOPIC);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ServerApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.setup;
|
||||
|
||||
import com.rabbitmq.client.BuiltinExchangeType;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class Setup {
|
||||
|
||||
private static final String ORDERS_QUEUE_NAME = "orders-queue";
|
||||
private static final String ORDERS_EXCHANGE_NAME = "orders-direct-exchange";
|
||||
private static final String ORDERS_ALTERNATE_EXCHANGE_NAME = "orders-alternate-exchange";
|
||||
private static final String ORDERS_ROUTING_KEY = "orders-routing-key";
|
||||
|
||||
public static void main(String[] args) throws IOException, TimeoutException {
|
||||
ConnectionFactory factory = new ConnectionFactory();
|
||||
factory.setHost("localhost");
|
||||
Connection connection = factory.newConnection();
|
||||
Channel channel = connection.createChannel();
|
||||
|
||||
Map<String, Object> exchangeArguments = new HashMap<>();
|
||||
exchangeArguments.put("alternate-exchange", ORDERS_ALTERNATE_EXCHANGE_NAME);
|
||||
channel.exchangeDeclare(ORDERS_EXCHANGE_NAME, BuiltinExchangeType.DIRECT, true, false, exchangeArguments);
|
||||
|
||||
Map<String, Object> queueArguments = new HashMap<>();
|
||||
queueArguments.put("x-message-ttl", 60000);
|
||||
queueArguments.put("x-max-priority", 10);
|
||||
channel.queueDeclare(ORDERS_QUEUE_NAME, true, false, false, queueArguments);
|
||||
|
||||
channel.queueBind(ORDERS_QUEUE_NAME, ORDERS_EXCHANGE_NAME, ORDERS_ROUTING_KEY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,2 @@
|
||||
# Memory configuration for Rabbit
|
||||
vm_memory_high_watermark.relative = 0.8
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.benchmark;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ConnectionPerChannelPublisherLiveTest {
|
||||
|
||||
@Test
|
||||
void whenConnectionPerChannel_thenRunBenchmark() throws Exception {
|
||||
// host, workerCount, iterations, payloadSize
|
||||
Arrays.asList(1,5,10,20,50,100,150).stream()
|
||||
.forEach(workers -> {
|
||||
ConnectionPerChannelPublisher.main(new String[]{"192.168.99.100", Integer.toString(workers), "1000", "4096"});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.benchmark;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SingleConnectionPublisherLiveTest {
|
||||
|
||||
@Test
|
||||
void whenSingleChannel_thenRunBenchmark() throws Exception {
|
||||
// host, workerCount, iterations, payloadSize
|
||||
Arrays.asList(1,5,10,20,50,100,150).stream()
|
||||
.forEach(workers -> {
|
||||
SingleConnectionPublisher.main(new String[]{"192.168.99.100", Integer.toString(workers), "1000", "4096"});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
## Spring AMQP
|
||||
|
||||
This module contains articles about Spring with the AMQP messaging system
|
||||
|
||||
## Relevant articles:
|
||||
|
||||
- [Messaging with Spring AMQP](https://www.baeldung.com/spring-amqp)
|
||||
- [RabbitMQ Message Dispatching with Spring AMQP](https://www.baeldung.com/rabbitmq-spring-amqp)
|
||||
- [Error Handling with Spring AMQP](https://www.baeldung.com/spring-amqp-error-handling)
|
||||
- [Exponential Backoff With Spring AMQP](https://www.baeldung.com/spring-amqp-exponential-backoff)
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
<?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>
|
||||
<artifactId>spring-amqp</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>spring-amqp</name>
|
||||
<description>Introduction to Spring-AMQP</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>messaging-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<start-class>com.baeldung.springamqp.simple.HelloWorldMessageApp</start-class>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.baeldung.springamqp.broadcast;
|
||||
|
||||
import org.springframework.amqp.core.*;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class BroadcastConfig {
|
||||
|
||||
private static final boolean NON_DURABLE = false;
|
||||
|
||||
public final static String FANOUT_QUEUE_1_NAME = "com.baeldung.spring-amqp-simple.fanout.queue1";
|
||||
public final static String FANOUT_QUEUE_2_NAME = "com.baeldung.spring-amqp-simple.fanout.queue2";
|
||||
public final static String FANOUT_EXCHANGE_NAME = "com.baeldung.spring-amqp-simple.fanout.exchange";
|
||||
|
||||
public final static String TOPIC_QUEUE_1_NAME = "com.baeldung.spring-amqp-simple.topic.queue1";
|
||||
public final static String TOPIC_QUEUE_2_NAME = "com.baeldung.spring-amqp-simple.topic.queue2";
|
||||
public final static String TOPIC_EXCHANGE_NAME = "com.baeldung.spring-amqp-simple.topic.exchange";
|
||||
public static final String BINDING_PATTERN_IMPORTANT = "*.important.*";
|
||||
public static final String BINDING_PATTERN_ERROR = "#.error";
|
||||
|
||||
@Bean
|
||||
public Declarables topicBindings() {
|
||||
Queue topicQueue1 = new Queue(TOPIC_QUEUE_1_NAME, NON_DURABLE);
|
||||
Queue topicQueue2 = new Queue(TOPIC_QUEUE_2_NAME, NON_DURABLE);
|
||||
|
||||
TopicExchange topicExchange = new TopicExchange(TOPIC_EXCHANGE_NAME, NON_DURABLE, false);
|
||||
|
||||
return new Declarables(topicQueue1, topicQueue2, topicExchange, BindingBuilder
|
||||
.bind(topicQueue1)
|
||||
.to(topicExchange)
|
||||
.with(BINDING_PATTERN_IMPORTANT), BindingBuilder
|
||||
.bind(topicQueue2)
|
||||
.to(topicExchange)
|
||||
.with(BINDING_PATTERN_ERROR));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Declarables fanoutBindings() {
|
||||
Queue fanoutQueue1 = new Queue(FANOUT_QUEUE_1_NAME, NON_DURABLE);
|
||||
Queue fanoutQueue2 = new Queue(FANOUT_QUEUE_2_NAME, NON_DURABLE);
|
||||
|
||||
FanoutExchange fanoutExchange = new FanoutExchange(FANOUT_EXCHANGE_NAME, NON_DURABLE, false);
|
||||
|
||||
return new Declarables(fanoutQueue1, fanoutQueue2, fanoutExchange, BindingBuilder
|
||||
.bind(fanoutQueue1)
|
||||
.to(fanoutExchange), BindingBuilder
|
||||
.bind(fanoutQueue2)
|
||||
.to(fanoutExchange));
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.baeldung.springamqp.broadcast;
|
||||
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import static com.baeldung.springamqp.broadcast.BroadcastConfig.*;
|
||||
|
||||
/**
|
||||
* Simple test application to send messages to rabbitMQ.
|
||||
*
|
||||
*<p>To run this particular application with mvn you use the following command:</p>
|
||||
* {@code
|
||||
* mvn spring-boot:run -Dstart-class=com.baeldung.springamqp.broadcast.BroadcastMessageApp
|
||||
* }
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class BroadcastMessageApp {
|
||||
|
||||
private static String ROUTING_KEY_USER_IMPORTANT_WARN = "user.important.warn";
|
||||
private static String ROUTING_KEY_USER_IMPORTANT_ERROR = "user.important.error";
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BroadcastMessageApp.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApplicationRunner runner(RabbitTemplate rabbitTemplate) {
|
||||
String message = " payload is broadcast";
|
||||
return args -> {
|
||||
rabbitTemplate.convertAndSend(BroadcastConfig.FANOUT_EXCHANGE_NAME, "", "fanout" + message);
|
||||
rabbitTemplate.convertAndSend(BroadcastConfig.TOPIC_EXCHANGE_NAME, ROUTING_KEY_USER_IMPORTANT_WARN, "topic important warn" + message);
|
||||
rabbitTemplate.convertAndSend(BroadcastConfig.TOPIC_EXCHANGE_NAME, ROUTING_KEY_USER_IMPORTANT_ERROR, "topic important error" + message);
|
||||
};
|
||||
}
|
||||
|
||||
@RabbitListener(queues = { FANOUT_QUEUE_1_NAME })
|
||||
public void receiveMessageFromFanout1(String message) {
|
||||
System.out.println("Received fanout 1 message: " + message);
|
||||
}
|
||||
|
||||
@RabbitListener(queues = { FANOUT_QUEUE_2_NAME })
|
||||
public void receiveMessageFromFanout2(String message) {
|
||||
System.out.println("Received fanout 2 message: " + message);
|
||||
}
|
||||
|
||||
@RabbitListener(queues = { TOPIC_QUEUE_1_NAME })
|
||||
public void receiveMessageFromTopic1(String message) {
|
||||
System.out.println("Received topic 1 (" + BINDING_PATTERN_IMPORTANT + ") message: " + message);
|
||||
}
|
||||
|
||||
@RabbitListener(queues = { TOPIC_QUEUE_2_NAME })
|
||||
public void receiveMessageFromTopic2(String message) {
|
||||
System.out.println("Received topic 2 (" + BINDING_PATTERN_ERROR + ") message: " + message);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.baeldung.springamqp.errorhandling;
|
||||
|
||||
import com.baeldung.springamqp.errorhandling.producer.MessageProducer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
public class ErrorHandlingApp {
|
||||
|
||||
@Autowired
|
||||
MessageProducer messageProducer;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ErrorHandlingApp.class, args);
|
||||
}
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void doSomethingAfterStartup() {
|
||||
messageProducer.sendMessage();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user