Total Pageviews

2019/04/05

[Spring boot] How To Do @Async in Spring

Setup Asynchronous configuration:
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
// enable asynchronous processing with Java configuration
@EnableAsync
public class AsyncConfig {

    @Bean("githubUserLookupExecutor")
    public ThreadPoolTaskExecutor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(1000);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadNamePrefix("Async-");
        return executor;
    }

}



Create a GitHub Lookup Service:
package com.example.service;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.CompletableFuture;

/**
 * GitHub Lookup Service
 */
@Slf4j
@Service
public class GitHubLookupService {

    @Value("${http.proxy.host}")
    private String host;

    @Value("${http.proxy.port}")
    private Integer port;

    /**
     * The method needs to be public so that it can be proxied.
     * And self-invocation doesn’t work because it bypasses the proxy and
     * calls the underlying method directly
     *
     * @param name user name
     * @return
     */
    @Async("githubUserLookupExecutor")
    public CompletableFuture<User> findUser(String name) {
        log.debug("looking up {}", name);

        String url = String.format("https://api.github.com/users/%s", name);
        User user = new RestTemplate(setupProxy()).getForObject(url, User.class);

        return CompletableFuture.completedFuture(user);
    }

    private SimpleClientHttpRequestFactory setupProxy() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
        requestFactory.setProxy(proxy);
        return requestFactory;
    }


    /**
     * Representation of a GitHub User (JSON to Object)
     */
    @Data
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class User {
        private String login;
        private String name;
        private String blog;
        private String location;
    }

}



Test code:
package com.example.test;

import com.example.service.GitHubLookupService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.CompletableFuture;

@SpringBootApplication
@ComponentScan(basePackages = "com.example")
@Slf4j
public class TestApplication {

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

    @Bean
    CommandLineRunner run(GitHubLookupService service) {
        return args -> {
            // Kick off multiple asynchronous lookups
            CompletableFuture<GitHubLookupService.User> junyuo = service.findUser("junyuo");
            CompletableFuture<GitHubLookupService.User> springProjects = service.findUser("Spring-Projects");
            CompletableFuture<GitHubLookupService.User> tensorflow = service.findUser("tensorflow");
            CompletableFuture<GitHubLookupService.User> dotnet = service.findUser("dotnet");
            CompletableFuture<GitHubLookupService.User> google = service.findUser("google");

            // Wait until they are all done
            CompletableFuture.allOf(junyuo, springProjects, tensorflow, dotnet, google).join();

            log.debug("user = {}", junyuo.get());
            log.debug("user = {}", dotnet.get());
            log.debug("user = {}", springProjects.get());
            log.debug("user = {}", google.get());
            log.debug("user = {}", tensorflow.get());
        };
    }

}


Console log:
2018-12-06 11:01:52.358  INFO 11440 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-12-06 11:01:52.361  INFO 11440 --- [           main] com.example.test.TestApplication         : Started TestApplication in 2.522 seconds (JVM running for 3.465)
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-3] com.example.service.GitHubLookupService  : looking up tensorflow
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-4] com.example.service.GitHubLookupService  : looking up dotnet
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-5] com.example.service.GitHubLookupService  : looking up google
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-2] com.example.service.GitHubLookupService  : looking up Spring-Projects
2018-12-06 11:01:52.370 DEBUG 11440 --- [        Async-1] com.example.service.GitHubLookupService  : looking up junyuo
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=junyuo, name=Albert Kuo, blog=http://albert-kuo.blogspot.com/, location=Taipei)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=dotnet, name=.NET Foundation, blog=http://www.dotnetfoundation.org, location=null)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=spring-projects, name=Spring, blog=http://spring.io/projects, location=null)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=google, name=Google, blog=https://opensource.google.com/, location=null)
2018-12-06 11:01:53.759 DEBUG 11440 --- [           main] com.example.test.TestApplication         : user = GitHubLookupService.User(login=tensorflow, name=null, blog=http://www.tensorflow.org, location=null)



No comments: