包阅导读总结
1. 关键词:Reactor Mono、Memoization、Spring、Cache、Optimization
2. 总结:
本文介绍了在 Spring 中使用 Reactor Mono 的 `cache()` 进行记忆化优化,包括其原理、优势、用例,通过示例展示了设置过程和代码输出,最后总结其对优化反应式应用的作用。
3. 主要内容:
– 介绍
– `Mono.cache()` 用于缓存 `Mono` 结果,供后续订阅者复用,避免昂贵操作重复执行。
– 优点包括提升性能、优化资源、保证一致性和可控缓存。
– 适用于昂贵计算、频繁数据访问、API 速率限制等场景。
– 示例设置
– 依赖设置,创建包含模拟昂贵操作的 `DataService` 类。
– 创建 `DataController` 类,暴露不同的 HTTP GET 映射端点。
– 创建 `MemoizationExampleApplication` 主类。
– 代码输出
– 无缓存时每次请求都有延迟。
– 有缓存时首次请求触发,后续复用。
– 带缓存时长时,超时长重新触发获取。
– 结论
`Mono.cache()` 可优化反应式应用,提高性能和效率。
思维导图:
文章地址:https://www.javacodegeeks.com/using-reactor-mono-cache-for-memoization-in-spring.html
文章来源:javacodegeeks.com
作者:Yatin Batra
发布时间:2024/7/30 16:01
语言:英文
总字数:1019字
预计阅读时间:5分钟
评分:80分
标签:Spring 响应式,记忆化,性能优化,Reactor Mono,Java
以下为原文内容
本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com
Memoization is an optimization technique used to speed up applications by storing the results of expensive function calls and reusing the cached result when the same inputs occur again. In the context of reactive programming, memoization helps avoid repeated executions of costly operations by caching their results. Let us delve into understanding how Spring Reactor Mono can be used as cache.
1. Introduction
The Mono.cache() operator in Project Reactor allows you to cache the result of a Mono and replay it to subsequent subscribers. This is particularly useful when dealing with expensive operations like network calls or database queries.
A marble diagram for Mono.cache()
would look like this:
(Expensive operation) --Mono--> (cache) --Mono--> (result)
In this diagram, the first subscriber triggers the expensive operation, and its result is cached. Subsequent subscribers receive the cached result without triggering the expensive operation again.
1.1 Advantages of Mono.cache()
- Improved Performance:
- Caching reduces the need for redundant computations or data fetch operations, leading to faster response times.
- Subsequent subscribers to the cached
Mono
can reuse the cached result, avoiding the overhead of repeated operations.
- Resource Optimization:
- Reduces load on backend services or databases by avoiding repeated calls for the same data.
- Optimizes network usage by minimizing the number of requests.
- Consistency:
- Ensures consistent results for multiple subscribers within the cache duration, as they all receive the same cached value.
- Controlled Caching:
- Allows fine-grained control over caching duration, ensuring data is refreshed periodically as needed.
1.2 Use Cases for Mono.cache()
- Expensive Computations:
- When performing computationally expensive operations, caching the result can significantly reduce the processing time for subsequent requests.
- Example: Complex data transformations, machine learning model inference.
- Frequent Data Access:
- When data is frequently accessed by multiple consumers but does not change often.
- Example: Configuration settings, user profile data in a session.
- API Rate Limiting:
- When dealing with external APIs that have rate limits, caching responses can help stay within those limits.
- Example: Third-party service integrations where the number of API calls is restricted.
- Static Data:
- Data that is static or changes infrequently can benefit from caching to avoid unnecessary fetch operations.
- Example: Country lists, static content for web pages.
- Database Query Results:
- Caching results of database queries that are costly in terms of execution time or resource usage.
- Example: Aggregated analytics data, reporting data.
- External Service Calls:
- When calling external services where latency can be high, caching the responses can improve overall application responsiveness.
- Example: Geolocation services, currency conversion rates.
2. Example Setup
Let’s set up a simple Spring boot example.
2.1 Dependencies
You can use Spring Initializr (https://start.spring.io/) to create a Spring Boot project. Once the project is successfully created and imported into the IDE of your choice add or update the required dependencies to pom.xml
(for Maven) or build.gradle
(for Gradle) file.
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.1</version> <relativePath /> <!-- lookup parent from repository --></parent><properties> <java.version>11</java.version></properties><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>
Similarly, you can add the required dependencies in the Gradle file if you use a Gradle build platform.
2.2 Create a Data service
Create a data service class containing a fetchData
method to simulate an expensive operation by delaying the emission of the data by 2 seconds using delayElement(…)
method. The Mono.fromSupplier
method is used to create a Mono
that emits data when subscribed to.
package com.example.memoizationexample;import org.springframework.stereotype.Service;import reactor.core.publisher.Mono;import java.time.Duration;@Servicepublic class DataService { public Mono<String> fetchData() { return Mono.fromSupplier(() -> { System.out.println("Fetching data from service..."); return "Data from service"; }).delayElement(Duration.ofSeconds(2)); }}
2.3 Create a controller class
Create a controller class and expose the different HTTP GET mapping endpoints.
/data-no-cache
: Fetches data without memoization. Each request will trigger thefetchData
method, simulating the 2-second delay./data-cache
: Fetches data with memoization usingMono.cache()
. The first request will trigger thefetchData
method and subsequent requests will return the cached result./data-cache-duration
: Fetches data with memoization usingMono.cache(Duration.ofSeconds(10))
. The first request will trigger thefetchData
method and subsequent requests within 10 seconds will return the cached result. After 10 seconds, the cache will expire, and a new fetch operation will be triggered.
package com.example.memoizationexample;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import reactor.core.publisher.Mono;@RestControllerpublic class DataController { private final DataService dataService; private final Mono<String> cachedData; private final Mono<String> cachedDataWithDuration; public DataController(DataService dataService) { this.dataService = dataService; this.cachedData = dataService.fetchData().cache(); this.cachedDataWithDuration = dataService.fetchData().cache(Duration.ofSeconds(10)); } @GetMapping("/data-no-cache") public Mono<String> getDataNoCache() { return dataService.fetchData(); } @GetMapping("/data-cache") public Mono<String> getDataWithCache() { return cachedData; } @GetMapping("/data-cache-duration") public Mono<String> getDataWithCacheDuration() { return cachedDataWithDuration; }}
2.4 Create a main class
Create a main class of the Spring boot application. The main()
method initializes the application.
package com.example.memoizationexample;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class MemoizationExampleApplication { public static void main(String[] args) { SpringApplication.run(MemoizationExampleApplication.class, args); }}
2.5 Code output
When you run the application using the mvn spring-boot:run
command open the browser to access the endpoints on the 8080 port number. If you need to change the default port number feel free to add the server.port
attribute in the application.properties
file.
2.5.1 Fetching data without memoization
Every request to /data-no-cache
will trigger the fetchData
method, leading to a 2-second delay for each request.
[2024-07-26 10:00:02] Fetching data from service...[2024-07-26 10:00:06] Fetching data from service...
2.5.2 Fetching Data With Memoization
The first request to /data-cache
will trigger the fetchData
method, and subsequent requests will return the cached result without delay. The cache log is implicit in Mono
.
[2024-07-26 10:01:02] Fetching data from service...[2024-07-26 10:01:04] Using cached data...
2.5.3 Fetching Data With Cache Duration
The first request to /data-cache-duration
will trigger the fetchData
method. Subsequent requests within 10 seconds will return the cached result. After 10 seconds, the cache will expire, and a new fetch operation will be triggered. The cache log is implicit in Mono
.
[2024-07-26 10:02:02] Fetching data from service...[2024-07-26 10:02:04] Using cached data...[2024-07-26 10:02:16] Fetching data from service...
3. Conclusion
Using Mono.cache()
in Project Reactor is a powerful way to optimize your reactive applications by memoizing the results of expensive operations. This ensures that costly computations or I/O operations are performed only once, improving performance and efficiency.