DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • How To Build a Google Photos Clone - Part 1
  • Enterprise RIA With Spring 3, Flex 4 and GraniteDS
  • Migrating Spring Java Applications to Azure App Service (Part 1: DataSources and Credentials)
  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)

Trending

  • Dropwizard vs. Micronaut: Unpacking the Best Framework for Microservices
  • Advancing Robot Vision and Control
  • Simplifying Multi-LLM Integration With KubeMQ
  • The Perfection Trap: Rethinking Parkinson's Law for Modern Engineering Teams
  1. DZone
  2. Coding
  3. Frameworks
  4. How to Split Up Synchronous and Asynchronous Parts of Your System in Java

How to Split Up Synchronous and Asynchronous Parts of Your System in Java

Learn how you can split up your system by synchronous and asynchronous parts using Java.

By 
Petr Bouda user avatar
Petr Bouda
DZone Core CORE ·
Updated Jun. 06, 19 · Tutorial
Likes (13)
Comment
Save
Tweet
Share
28.1K Views

Join the DZone community and get the full member experience.

Join For Free

A lot of developers say that it's very complicated to switch their applications over to asynchronous processing because they have a web app with naturally synchronous communication. In this post, I would like to introduce one way to do it using a few well-known libraries and tools to use while designing their systems. The example below is written in Java but I believe it's more about the basic principles and the same app can be re-written into any language.

Tools and libraries needed:

  • Spring Boot
  • RabbitMQ

Web Application

A web application is written in Spring MVC and running on Tomcat. What it does is send a string to a queue (the start of asynchronous communication) and waiting for a message in a different queue to send it back as an HTTP response.

First, we need to define several dependencies and then wait for Spring Boot to do all necessary auto-configuration magic.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>com.thedeanda</groupId>
        <artifactId>lorem</artifactId>
    </dependency>
</dependencies>
@SpringBootApplication
public class BlockingApplication {

    public static void main(String[] args) {
        SpringApplication.run(BlockingApplication.class, args);
    }

    @RestController
    public static class MessageController {

        private final RabbitTemplate rabbitTemplate;

        public MessageController(CachingConnectionFactory connectionFactory) {
            this.rabbitTemplate = new RabbitTemplate(connectionFactory);
        }

        @GetMapping("invoke")
        public String sendMessage() {
            Message response = rabbitTemplate.sendAndReceive("uppercase", null, request());
            return new String(response.getBody());
        }

        private static Message request() {
            Lorem LOREM = LoremIpsum.getInstance();
            String name = LOREM.getFirstName() + " " + LOREM.getLastName();
            return new Message(name.getBytes(), new MessageProperties());
        }
    }

    @Bean
    public CachingConnectionFactory connectionFactory() {
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setAddresses("localhost:5672");
        factory.setUsername("admin");
        factory.setPassword("admin");
        return factory;
    }
}


Consumer Application

The second application is just the RabbitMQ consumer waiting for messages, calling an uppercase function on the consumed string, and then sending the result back to the output queue.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
</dependencies>
@SpringBootApplication
public class ServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }

    public static class MessageListener {

        public String handleMessage(byte[] message) {
            Random rand = new Random();
            // Obtain a number between [0 - 49] + 50 = [50 - 99]
            int n = rand.nextInt(50) + 50;

            String content = new String(message);
            try {
                Thread.sleep(n);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return content.toUpperCase();
        }
    }

    @Bean
    public CachingConnectionFactory connectionFactory() {
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setAddresses("localhost:5672");
        factory.setUsername("admin");
        factory.setPassword("admin");
        return factory;
    }

    @Bean
    public SimpleMessageListenerContainer serviceListenerContainer() {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory());
        container.setConcurrentConsumers(20);
        container.setMaxConcurrentConsumers(40);
        container.setQueueNames("uppercase_messages");
        container.setMessageListener(new MessageListenerAdapter(new MessageListener()));
        return container;
    }
}


How Does it Work Under the Hood?

After an application startup and the first invocation of our endpoint, we can see that Spring AMQP support automatically created a new reply queue and waits for a response from our service application.

2019-05-12 17:23:21.451  INFO 4574 --- [nio-8080-exec-1] .l.DirectReplyToMessageListenerContainer : Container initialized for queues: [amq.rabbitmq.reply-to]
2019-05-12 17:23:21.457  INFO 4574 --- [nio-8080-exec-1] .l.DirectReplyToMessageListenerContainer : SimpleConsumer [queue=amq.rabbitmq.reply-to, consumerTag=amq.ctag-VF-iqD9rLEuljIBstbCI1A identity=10e58093] started


If we look into a message in the consumer application, we can see that Spring automatically propagated the information about reply queue along with correlation id, which is used to pass it back to the web application to be able to pair requests and responses together.

This is actually where the magic happens. Of course, if you want to make it more sophisticated, you can have more services included in collaboration and then put a final response for web application into a different queue than the automatically generated one just with a proper correlation id. Also, don't forget to set a reasonable timeout up.

There is also one big disadvantage of this solution — application throughput. I made it intentionally so that I can follow up on this post with a further investigation of the AsyncProfiler! But currently, we are using Tomcat as primary HTTP Server with a default of 200 threads, which means our application is not able to handle more than 200 messages concurrently because our server's threads are waiting on RabbitMQ reply queue for a response until the message comes in or the timeout occurs.

Thank you for reading this post, and stay tuned for the followup! If you would like to try this out yourself, just check out my GitHub repository. If you like being notified about new posts, then start following me on Twitter: @p_bouda.

Spring Framework application Web application Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • How To Build a Google Photos Clone - Part 1
  • Enterprise RIA With Spring 3, Flex 4 and GraniteDS
  • Migrating Spring Java Applications to Azure App Service (Part 1: DataSources and Credentials)
  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!