Coder Social home page Coder Social logo

buzzardo / gs-async-method Goto Github PK

View Code? Open in Web Editor NEW

This project forked from spring-guides/gs-async-method

0.0 1.0 0.0 968 KB

Creating Asynchronous Methods :: Learn how to create asynchronous service methods.

Home Page: https://spring.io/guides/gs/async-method/

Java 92.30% Shell 7.70%

gs-async-method's Introduction

This guide walks you through creating asynchronous queries to GitHub. The focus is on the asynchronous part, a feature often used when scaling services.

What You Will build

You will build a lookup service that queries GitHub user information and retrieves data through GitHub’s API. One approach to scaling services is to run expensive jobs in the background and wait for the results by using Java’s CompletableFuture interface. Java’s CompletableFuture is an evolution from the regular Future. It makes it easy to pipeline multiple asynchronous operations and merge them into a single asynchronous computation.

Starting with Spring Initializr

For all Spring applications, you should start with the Spring Initializr. The Initializr offers a fast way to pull in all the dependencies you need for an application and does a lot of the set up for you. This example needs only the Spring Web dependency. The following image shows the Initializr set up for this sample project:

initializr
Note
The preceding image shows the Initializr with Maven chosen as the build tool. You can also use Gradle. It also shows values of com.example and async-method as the Group and Artifact, respectively. You will use those values throughout the rest of this sample.

The following listing shows the pom.xml file created when you choose Maven:

link:complete/pom.xml[role=include]

The following listing shows the build.gradle file created when you choose Gradle:

link:complete/build.gradle[role=include]

Create a Representation of a GitHub User

Before you can create a GitHub lookup service, you need to define a representation for the data you will retrieve through GitHub’s API.

To model the user representation, create a resource representation class. To do so, provide a plain old Java object with fields, constructors, and accessors, as the following example (from src/main/java/com/example/asyncmethod/User.java) shows:

link:complete/src/main/java/com/example/asyncmethod/User.java[role=include]

Spring uses the Jackson JSON library to convert GitHub’s JSON response into a User object. The @JsonIgnoreProperties annotation tells Spring to ignore any attributes not listed in the class. This makes it easy to make REST calls and produce domain objects.

In this guide, we grab only the name and the blog URL for demonstration purposes.

Create a GitHub Lookup Service

Next, you need to create a service that queries GitHub to find user information. The following listing (from src/main/java/com/example/asyncmethod/GitHubLookupService.java) shows how to do so:

link:complete/src/main/java/com/example/asyncmethod/GitHubLookupService.java[role=include]

The GitHubLookupService class uses Spring’s RestTemplate to invoke a remote REST point (api.github.com/users/) and then convert the answer into a User object. Spring Boot automatically provides a RestTemplateBuilder that customizes the defaults with any auto-configuration bits (that is, MessageConverter).

The class is marked with the @Service annotation, making it a candidate for Spring’s component scanning to detect and add to the application context.

The findUser method is flagged with Spring’s @Async annotation, indicating that it should run on a separate thread. The method’s return type is CompletableFuture<User> instead of User, a requirement for any asynchronous service. This code uses the completedFuture method to return a CompletableFuture instance that is already completed with result of the GitHub query.

Note
Creating a local instance of the GitHubLookupService class does NOT allow the findUser method to run asynchronously. It must be created inside a @Configuration class or picked up by @ComponentScan.

The timing for GitHub’s API can vary. To demonstrate the benefits later in this guide, an extra delay of one second has been added to this service.

Make the Application Executable

To run a sample, you can create an executable jar. Spring’s @Async annotation works with web applications, but you need not set up a web container to see its benefits. The following listing (from src/main/java/com/example/asyncmethod/AsyncMethodApplication.java) shows how to do so:

link:complete/src/main/java/com/example/asyncmethod/AsyncMethodApplication.java[role=include]
Note
The Spring Initalizr created an AsyncMethodApplication class for you. You can find it in the zip file that you downloaded from the Spring Initalizr (in src/main/java/com/example/asyncmethod/AsyncMethodApplication.java). You can either copy that class to your project and then modify it or copy the class from the preceding listing.

The @EnableAsync annotation switches on Spring’s ability to run @Async methods in a background thread pool. This class also customizes the Executor by defining a new bean. Here, the method is named taskExecutor, since this is the specific method name for which Spring searches. In our case, we want to limit the number of concurrent threads to two and limit the size of the queue to 500. There are many more things you can tune. If you do not define an Executor bean, Spring creates a SimpleAsyncTaskExecutor and uses that.

There is also a CommandLineRunner that injects the GitHubLookupService and calls that service three times to demonstrate the method is executed asynchronously.

You also need a class to run the application. You can find that in src/main/java/com/example/asyncmethod/AppRunner.java. The following listing shows that class:

link:complete/src/main/java/hello/AppRunner.java[role=include]

The application shows logging output, showing each query to GitHub. With the help of the allOf factory method, we create an array of CompletableFuture objects. By calling the join method, it is possible to wait for the completion of all of the CompletableFuture objects.

The following listing shows typical output from this sample application:

2016-09-01 10:25:21.295  INFO 17893 --- [ GithubLookup-2] hello.GitHubLookupService                : Looking up CloudFoundry
2016-09-01 10:25:21.295  INFO 17893 --- [ GithubLookup-1] hello.GitHubLookupService                : Looking up PivotalSoftware
2016-09-01 10:25:23.142  INFO 17893 --- [ GithubLookup-1] hello.GitHubLookupService                : Looking up Spring-Projects
2016-09-01 10:25:24.281  INFO 17893 --- [           main] hello.AppRunner                          : Elapsed time: 2994
2016-09-01 10:25:24.282  INFO 17893 --- [           main] hello.AppRunner                          : --> User [name=Pivotal Software, Inc., blog=http://pivotal.io]
2016-09-01 10:25:24.282  INFO 17893 --- [           main] hello.AppRunner                          : --> User [name=Cloud Foundry, blog=https://www.cloudfoundry.org/]
2016-09-01 10:25:24.282  INFO 17893 --- [           main] hello.AppRunner                          : --> User [name=Spring, blog=http://spring.io/projects]

Note that the first two calls happen in separate threads (GithubLookup-2, GithubLookup-1) and the third one is parked until one of the two threads became available. To compare how long this takes without the asynchronous feature, try commenting out the @Async annotation and runing the service again. The total elapsed time should increase noticeably, because each query takes at least a second. You can also tune the Executor to increase the corePoolSize attribute for instance.

Essentially, the longer the task takes and the more tasks are invoked simultaneously, the more benefit you see from making things asynchronous. The trade off is handling the CompletableFuture interface. It adds a layer of indirection, because you are no longer dealing directly with the results.

Summary

Congratulations! You have just developed an asynchronous service that lets you scale multiple calls at once.

gs-async-method's People

Contributors

altfatterz avatar bclozel avatar btalbott avatar buzzardo avatar cbeams avatar gregturn avatar jchoffmann avatar royclarkson avatar snicoll avatar spring-operator avatar tiwarivikash avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.