BAEL-7143: virtual threads vs webflux
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.spring.reactive.performance;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.spring.reactive.performance;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class KafkaTemplate<K, V> {
|
||||
|
||||
// For simplicity in this example and article, an actual Kafka client isn't utilized.
|
||||
// The focus remains on demonstrating the basic principles without the complexities of a full Kafka client setup.
|
||||
|
||||
public CompletableFuture<Void> send(String topic, K key, V value) {
|
||||
System.out.println("Sending message to topic: " + topic + " with value: " + value);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package com.baeldung.spring.reactive.performance;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public record ProductAddedToCartEvent(String productId, BigDecimal price, String currency, String cartId) {
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.spring.reactive.performance.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public record Price(BigDecimal value, String currency) {
|
||||
public Price applyDiscount(BigDecimal discount) {
|
||||
return new Price(value.subtract(discount), currency);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.spring.reactive.performance.model;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
@Document(collation = "products")
|
||||
public record Product (
|
||||
@Id
|
||||
String id,
|
||||
String name,
|
||||
BigDecimal basePriceValue,
|
||||
String currency,
|
||||
Category category
|
||||
) {
|
||||
|
||||
public Price basePrice() {
|
||||
return new Price(basePriceValue, currency);
|
||||
}
|
||||
|
||||
public enum Category {
|
||||
ELECTRONICS(false),
|
||||
CLOTHING(true),
|
||||
ACCESSORIES(false),
|
||||
GARDENING(false),
|
||||
SPORTS(true);
|
||||
|
||||
private final boolean eligibleForPromotion;
|
||||
|
||||
Category(boolean eligibleForPromotion) {
|
||||
this.eligibleForPromotion = eligibleForPromotion;
|
||||
}
|
||||
|
||||
public boolean isEligibleForDiscount() {
|
||||
return eligibleForPromotion;
|
||||
}
|
||||
|
||||
public boolean notEligibleForPromotion() {
|
||||
return !eligibleForPromotion;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.spring.reactive.performance.virtualthreads;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
class DiscountService {
|
||||
|
||||
public BigDecimal discountForProduct(String productId) {
|
||||
return BigDecimal.valueOf(10);
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.baeldung.spring.reactive.performance.virtualthreads;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import com.baeldung.spring.reactive.performance.model.Product;
|
||||
|
||||
interface ProductRepository extends MongoRepository<Product, String> {
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.spring.reactive.performance.virtualthreads;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.baeldung.spring.reactive.performance.KafkaTemplate;
|
||||
import com.baeldung.spring.reactive.performance.ProductAddedToCartEvent;
|
||||
import com.baeldung.spring.reactive.performance.model.Price;
|
||||
import com.baeldung.spring.reactive.performance.model.Product;
|
||||
|
||||
class ProductService {
|
||||
private final String PRODUCT_ADDED_TO_CART_TOPIC = "product-added-to-cart";
|
||||
|
||||
private final ProductRepository repository;
|
||||
private final DiscountService discountService;
|
||||
private final KafkaTemplate<String, ProductAddedToCartEvent> kafkaTemplate;
|
||||
|
||||
public ProductService(ProductRepository repository, DiscountService discountService) {
|
||||
this.repository = repository;
|
||||
this.discountService = discountService;
|
||||
this.kafkaTemplate = new KafkaTemplate<>();
|
||||
}
|
||||
|
||||
public void addProductToCart(String productId, String cartId) {
|
||||
Thread.startVirtualThread(() -> computePriceAndPublishMessage(productId, cartId));
|
||||
}
|
||||
|
||||
private void computePriceAndPublishMessage(String productId, String cartId) {
|
||||
Product product = repository.findById(productId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("not found!"));
|
||||
|
||||
Price price = computePrice(productId, product);
|
||||
|
||||
var event = new ProductAddedToCartEvent(productId, price.value(), price.currency(), cartId);
|
||||
kafkaTemplate.send(PRODUCT_ADDED_TO_CART_TOPIC, cartId, event);
|
||||
}
|
||||
|
||||
private Price computePrice(String productId, Product product) {
|
||||
if (product.category()
|
||||
.isEligibleForDiscount()) {
|
||||
BigDecimal discount = discountService.discountForProduct(productId);
|
||||
return product.basePrice()
|
||||
.applyDiscount(discount);
|
||||
}
|
||||
return product.basePrice();
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.spring.reactive.performance.webflux;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class DiscountService {
|
||||
public Mono<BigDecimal> discountForProduct(String productId) {
|
||||
return Mono.just(BigDecimal.valueOf(10));
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.baeldung.spring.reactive.performance.webflux;
|
||||
|
||||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
|
||||
|
||||
import com.baeldung.spring.reactive.performance.model.Product;
|
||||
|
||||
interface ProductRepository extends ReactiveMongoRepository<Product, String> {
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.baeldung.spring.reactive.performance.webflux;
|
||||
|
||||
import com.baeldung.spring.reactive.performance.KafkaTemplate;
|
||||
import com.baeldung.spring.reactive.performance.ProductAddedToCartEvent;
|
||||
import com.baeldung.spring.reactive.performance.model.Price;
|
||||
import com.baeldung.spring.reactive.performance.model.Product;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
class ProductService {
|
||||
private final String PRODUCT_ADDED_TO_CART_TOPIC = "product-added-to-cart";
|
||||
|
||||
private final ProductRepository repository;
|
||||
private final DiscountService discountService;
|
||||
private final KafkaTemplate<String, ProductAddedToCartEvent> kafkaTemplate;
|
||||
|
||||
public ProductService(ProductRepository repository, DiscountService discountService) {
|
||||
this.repository = repository;
|
||||
this.discountService = discountService;
|
||||
this.kafkaTemplate = new KafkaTemplate<>();
|
||||
}
|
||||
|
||||
public void addProductToCart(String productId, String cartId) {
|
||||
repository.findById(productId)
|
||||
.switchIfEmpty(Mono.error(() -> new IllegalArgumentException("not found!")))
|
||||
.flatMap(this::computePrice)
|
||||
.map(price -> new ProductAddedToCartEvent(productId, price.value(), price.currency(), cartId))
|
||||
.subscribe(event -> kafkaTemplate.send(PRODUCT_ADDED_TO_CART_TOPIC, cartId, event));
|
||||
}
|
||||
|
||||
private Mono<Price> computePrice(Product product) {
|
||||
if (product.category()
|
||||
.isEligibleForDiscount()) {
|
||||
return discountService.discountForProduct(product.id())
|
||||
.map(product.basePrice()::applyDiscount);
|
||||
}
|
||||
return Mono.just(product.basePrice());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.spring.reactive.performance;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
public class ApplicationUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user