Spring指南之创建异步方法

请参见官方文档Spring指南之创建异步方法
请参见Spring Framework官方文档之Task Execution and Scheduling(任务执行与调度)
参见github代码

一.简介

本指南将引导你创建到GitHub的异步查询。重点是异步部分,这是scaling services时经常使用的一个特性。

二.你将创造什么(What You Will Build)

你将构建一个通过GitHub的API查询GitHub用户信息和检索数据的查找服务。scaling services 的一种方法是在后台运行开销很大的作业,然后使用Java的CompletableFuture接口等待结果。Java的CompletableFuture是从常规Future演变而来的。它可以很容易地将多个异步操作串联起来,并将它们合并到单个异步计算中。

三.创建项目

创建spring boot项目
单击Dependencies并选择Spring Web。

3.1 创建github用户实体类
public class GitHubUser {
    //登陆账号
    private String login;
    public String getLogin() {
        return login;
    }
    public void setLogin(String login) {
        this.login = login;
    }
    @Override
    public String toString() {
        return "GitHubUser{" +
                "login='" + login + '\'' +
                '}';
    }
}
3.1 创建 GitHub 查找服务
@Service
public class GitHubLookupService {
    private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);
    //使用Spring的RestTemplate来调用一个远程REST点(api.github.com/users/),然后将答案转换为GitHubUser对象。
    private final RestTemplate restTemplate;
    //Spring Boot自动提供了一个RestTemplateBuilder,它可以用任何自动配置位(即MessageConverter)自定义默认值。
    public GitHubLookupService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    /**
     * findUser方法用Spring的@Async注释标记,表明它应该在一个单独的线程上运行。该方法的返回类型是CompletableFuture,而不是GitHubUser,这是任何异步服务的要求。
     * 这段代码使用completedFuture方法返回一个CompletableFuture实例,它已经完成了GitHub查询的结果。
     */
    @Async
    public CompletableFuture<GitHubUser> findUser(String loginAccount) throws InterruptedException {
        logger.info("Looking up " + loginAccount + "comes from Thread " + Thread.currentThread().getName());
        String url = String.format("https://api.github.com/users/%s", loginAccount);
        GitHubUser results = restTemplate.getForObject(url, GitHubUser.class);
        // Artificial delay of 1s for demonstration purposes(为演示目的,人工延迟5秒)
        Thread.sleep(5000L);
        return CompletableFuture.completedFuture(results);
    }
}
3.2 创建 GitHub 查找控制器
@Controller
@RequestMapping("/github")
public class GitHubLookupController {
    private static final Logger logger = LoggerFactory.getLogger(GitHubLookupController.class);
    private final GitHubLookupService gitHubLookupService;
    public GitHubLookupController(GitHubLookupService gitHubLookupService) {
        this.gitHubLookupService = gitHubLookupService;
    }

    @RequestMapping("/findUser")
    @ResponseBody
    public List<GitHubUser> findUser() throws InterruptedException, ExecutionException {
        //开始计时
        long start = System.currentTimeMillis();
        //触发多个异步查找
        CompletableFuture<GitHubUser> future1 = gitHubLookupService.findUser("PivotalSoftware");
        CompletableFuture<GitHubUser> future2 = gitHubLookupService.findUser("CloudFoundry");
        CompletableFuture<GitHubUser> future3 = gitHubLookupService.findUser("Spring-Projects");
        CompletableFuture<GitHubUser> future4 = gitHubLookupService.findUser("xxxxxxxx");
        //等待它们全部完成
        CompletableFuture.allOf(future1, future2, future3, future4).join();
        //输出结果,包括运行时间
        logger.info("Elapsed time:" + (System.currentTimeMillis() - start));
        logger.info("--> " + future1.get());
        logger.info("--> " + future2.get());
        logger.info("--> " + future3.get());
        logger.info("--> " + future4.get());
        return Arrays.asList(future1.get(), future2.get(), future3.get(), future4.get());
    }
}

四.postman测试

在这里插入图片描述

1.请注意,前两个调用发生在不同的线程中(GithubLookup-2、GithubLookup-1),第三、四个调用被暂停,直到其中一个线程可用。要比较不使用异步功能需要多长时间,请尝试去掉@Async注释并再次运行该服务。总运行时间应该显著增加,因为每个查询至少需要五秒钟。例如,还可以调整Executor以增加corePoolSize属性。本质上,任务花费的时间越长,同时调用的任务越多,实现异步化的好处就越多。取舍是处理CompletableFuture接口。它增加了一层间接性,因为您不再直接处理结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值