Spring认证指南|了解如何创建异步服务方法。
Posted IT胶囊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring认证指南|了解如何创建异步服务方法。相关的知识,希望对你有一定的参考价值。
原标题:Spring认证指南|了解如何创建异步服务方法。
本指南将指导您创建对 GitHub 的异步查询。重点是异步部分,这是扩展服务时经常使用的功能。
你将建造什么
您将构建一个查询服务来查询 GitHub 用户信息并通过 GitHub 的 API 检索数据。CompletableFuture扩展服务的一种方法是在后台运行昂贵的作业并使用 Java 的接口等待结果。JavaCompletableFuture是从常规Future. 它可以轻松地将多个异步操作流水线化并将它们合并到一个异步计算中。
你需要什么
- 约15分钟
- 最喜欢的文本编辑器或 IDE
- JDK 1.8或更高版本
- Gradle 4+或Maven 3.2+
- 您还可以将代码直接导入 IDE:
- 弹簧工具套件 (STS)
- IntelliJ IDEA
如何完成本指南
像大多数 Spring入门指南一样,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都会得到工作代码。
要从头开始,请继续从 Spring Initializr 开始。
要跳过基础知识,请执行以下操作:
- 下载并解压本指南的源代码库,或使用Git克隆它:git clone https://github.com/spring-guides/gs-async-method.git
- 光盘进入gs-async-method/initial
- 跳转到创建 GitHub 用户的表示。
完成后,您可以对照中的代码检查结果gs-async-method/complete。
从 Spring Initializr 开始
您可以使用这个预先初始化的项目并单击 Generate 下载 ZIP 文件。此项目配置为适合本教程中的示例。
手动初始化项目:
- 导航到https://start.spring.io。该服务提取应用程序所需的所有依赖项,并为您完成大部分设置。
- 选择 Gradle 或 Maven 以及您要使用的语言。本指南假定您选择了 Java。
- 单击Dependencies并选择Spring Web。
- 单击生成。
- 下载生成的 ZIP 文件,该文件是根据您的选择配置的 Web 应用程序的存档。
如果您的 IDE 具有 Spring Initializr 集成,您可以从您的 IDE 完成此过程。
你也可以从 Github 上 fork 项目并在你的 IDE 或其他编辑器中打开它。
创建 GitHub 用户的表示
在创建 GitHub 查找服务之前,您需要为将通过 GitHub 的 API 检索的数据定义一个表示。
要对用户表示进行建模,请创建资源表示类。为此,请提供一个带有字段、构造函数和访问器的普通 Java 对象,如以下示例(来自src/main/java/com/example/asyncmethod/User.java)所示:
package com.example.asyncmethod;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown=true)
public class User
private String name;
private String blog;
public String getName()
return name;
public void setName(String name)
this.name = name;
public String getBlog()
return blog;
public void setBlog(String blog)
this.blog = blog;
@Override
public String toString()
return "User [name=" + name + ", blog=" + blog + "]";
复制
Spring 使用Jackson JSON库将 GitHub 的 JSON 响应转换为User对象。@JsonIgnoreProperties注释告诉 Spring 忽略类中未列出的任何属性。这使得进行 REST 调用和生成域对象变得容易。
在本指南中,我们仅获取name和blogURL 用于演示目的。
创建 GitHub 查找服务
接下来,您需要创建一个查询 GitHub 以查找用户信息的服务。以下清单(来自src/main/java/com/example/asyncmethod/GitHubLookupService.java)显示了如何执行此操作:
package com.example.asyncmethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.CompletableFuture;
@Service
public class GitHubLookupService
private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);
private final RestTemplate restTemplate;
public GitHubLookupService(RestTemplateBuilder restTemplateBuilder)
this.restTemplate = restTemplateBuilder.build();
@Async
public CompletableFuture<User> findUser(String user) throws InterruptedException
logger.info("Looking up " + user);
String url = String.format("https://api.github.com/users/%s", user);
User results = restTemplate.getForObject(url, User.class);
// Artificial delay of 1s for demonstration purposes
Thread.sleep(1000L);
return CompletableFuture.completedFuture(results);
复制
该类GitHubLookupService使用 SpringRestTemplate调用远程 REST 点 (api.github.com/users/),然后将答案转换为User对象。Spring Boot 自动提供一个RestTemplateBuilder使用任何自动配置位(即MessageConverter)自定义默认值的选项。
该类被标记为@Service注解,使其成为 Spring 组件扫描的候选对象,以检测并添加到应用程序上下文中。
该findUser方法使用 Spring 的@Async注释进行标记,表明它应该在单独的线程上运行。该方法的返回类型CompletableFuture<User>不是User,而是任何异步服务的要求。此代码使用该completedFuture方法返回CompletableFuture已完成 GitHub 查询结果的实例。
创建GitHubLookupService该类的本地实例不允许该findUser方法异步运行。它必须在@Configuration类中创建或由@ComponentScan.
GitHub API 的时间可能会有所不同。为了在本指南后面的部分中展示好处,此服务增加了一秒的额外延迟。
使应用程序可执行
要运行示例,您可以创建一个可执行 jar。Spring 的@Async注解适用于 Web 应用程序,但您无需设置 Web 容器即可看到它的好处。以下清单(来自src/main/java/com/example/asyncmethod/AsyncMethodApplication.java)显示了如何执行此操作:
package com.example.asyncmethod;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@SpringBootApplication
@EnableAsync
public class AsyncMethodApplication
public static void main(String[] args)
// close the application context to shut down the custom ExecutorService
SpringApplication.run(AsyncMethodApplication.class, args).close();
@Bean
public Executor taskExecutor()
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
Spring
InitializrAsyncMethodApplication为您创建了一个类。src/main/java/com/example/asyncmethod/AsyncMethodApplication.java您可以在从 Spring Initializr (in )下载的 zip 文件中找到它。您可以将该类复制到您的项目中,然后对其进行修改,也可以从前面的清单中复制该类。
@SpringBootApplication是一个方便的注释,它添加了以下所有内容:
- @Configuration: 将类标记为应用程序上下文的 bean 定义源。
- @EnableAutoConfiguration:告诉 Spring Boot 根据类路径设置、其他 bean 和各种属性设置开始添加 bean。例如,如果spring-webmvc位于类路径上,则此注释将应用程序标记为 Web 应用程序并激活关键行为,例如设置DispatcherServlet.
- @ComponentScan: 告诉 Spring 在包中查找其他组件、配置和服务com/example,让它找到控制器。
该main()方法使用 Spring Boot 的SpringApplication.run()方法来启动应用程序。您是否注意到没有一行 XML?也没有web.xml文件。这个 Web 应用程序是 100% 纯 Java,您不必处理任何管道或基础设施的配置。
@EnableAsync注释开启了 Spring@Async在后台线程池中运行方法的能力。这个类还Executor通过定义一个新的bean来定制。在这里,方法名为taskExecutor,因为这是Spring 搜索的特定方法名称。在我们的例子中,我们希望将并发线程的数量限制为两个,并将队列的大小限制为 500。您可以调整更多的东西。如果你没有定义一个Executorbean,Spring 会创建一个SimpleAsyncTaskExecutor并使用它。
还有一个CommandLineRunner是注入GitHubLookupService并调用该服务3次来演示该方法是异步执行的。
您还需要一个类来运行应用程序。你可以在src/main/java/com/example/asyncmethod/AppRunner.java. 以下清单显示了该类:
package com.example.asyncmethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
@Component
public class AppRunner implements CommandLineRunner
private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);
private final GitHubLookupService gitHubLookupService;
public AppRunner(GitHubLookupService gitHubLookupService)
this.gitHubLookupService = gitHubLookupService;
@Override
public void run(String... args) throws Exception
// Start the clock
long start = System.currentTimeMillis();
// Kick of multiple, asynchronous lookups
CompletableFuture<User> page1 = gitHubLookupService.findUser("PivotalSoftware");
CompletableFuture<User> page2 = gitHubLookupService.findUser("CloudFoundry");
CompletableFuture<User> page3 = gitHubLookupService.findUser("Spring-Projects");
// Wait until they are all done
CompletableFuture.allOf(page1,page2,page3).join();
// Print results, including elapsed time
logger.info("Elapsed time: " + (System.currentTimeMillis() - start));
logger.info("--> " + page1.get());
logger.info("--> " + page2.get());
logger.info("--> " + page3.get());
复制
构建一个可执行的 JAR
您可以使用 Gradle 或 Maven 从命令行运行应用程序。您还可以构建一个包含所有必要依赖项、类和资源的单个可执行 JAR 文件并运行它。构建可执行 jar 可以在整个开发生命周期、跨不同环境等中轻松地作为应用程序交付、版本化和部署服务。
如果您使用 Gradle,则可以使用./gradlew bootRun. 或者,您可以使用构建 JAR 文件./gradlew build,然后运行 JAR 文件,如下所示:
java -jar build/libs/gs-async-method-0.1.0.jar
如果您使用 Maven,则可以使用./mvnw spring-boot:run. 或者,您可以使用构建 JAR 文件,./mvnw clean package然后运行该 JAR 文件,如下所示:
java -jar 目标/gs-async-method-0.1.0.jar
此处描述的步骤创建了一个可运行的 JAR。您还可以构建经典的 WAR 文件。
该应用程序显示日志记录输出,显示对 GitHub 的每个查询。在allOf工厂方法的帮助下,我们创建了一个对象数组CompletableFuture。通过调用该join方法,可以等待所有CompletableFuture对象的完成。
以下清单显示了此示例应用程序的典型输出:
2016-09-01 10:25:21.295 INFO 17893 --- [GithubLookup-2] hello.GitHubLookupService:查找 CloudFoundry
2016-09-01 10:25:21.295 INFO 17893 --- [GithubLookup-1] hello.GitHubLookupService:查找 PivotalSoftware
2016-09-01 10:25:23.142 INFO 17893 --- [GithubLookup-1] hello.GitHubLookupService:查找 Spring-Projects
2016-09-01 10:25:24.281 INFO 17893 --- [main] hello.AppRunner:经过时间:2994
2016-09-01 10:25:24.282 INFO 17893 --- [main] hello.AppRunner : --> 用户 [name=Pivotal Software, Inc., blog=https://pivotal.io]
2016-09-01 10:25:24.282 INFO 17893 --- [main] hello.AppRunner : --> 用户 [name=Cloud Foundry, blog=https://www.cloudfoundry.org/]
2016-09-01 10:25:24.282 INFO 17893 --- [main] hello.AppRunner : --> 用户 [name=Spring, blog=https://spring.io/projects]
请注意,前两个调用发生在单独的线程 ( GithubLookup-2, GithubLookup-1) 中,第三个调用被停放,直到两个线程之一可用。要比较没有异步功能需要多长时间,请尝试注释掉@Async注释并再次运行服务。总运行时间应该会显着增加,因为每个查询至少需要一秒钟。例如,您还可以调整Executor以增加corePoolSize属性。
本质上,任务花费的时间越长,同时调用的任务越多,您从异步处理中看到的好处就越大。权衡是处理CompletableFuture接口。它增加了一层间接性,因为您不再直接处理结果。
概括
恭喜!您刚刚开发了一个异步服务,可让您一次扩展多个调用。
以上是关于Spring认证指南|了解如何创建异步服务方法。的主要内容,如果未能解决你的问题,请参考以下文章
Spring认证指南:了解如何使用 Spring 执行表单验证