通过优锐课的java学习分享中,讨论随着NoSQL数据库的普及,MongoDB迅速普及。我们可以看到,码了很多专业的相关知识, 分享给大家参考学习。
Spring Data MongoDB已更新,以利用Spring Framework 5中引入的反应式编程模型。随后是对NoSQL数据库(例如MongoDB,Cassandra和Redis)的反应式数据访问的支持。
随着NoSQL数据库的普及,MongoDB在企业和Spring社区中迅速普及。
在本文中,我们将介绍如何使用Spring Framework 5和Spring Data MongoDB中的反应式编程功能。
如果你是反应式编程的新手,建议你首先阅读Java中的反应式流是什么?帖子,然后再阅读Spring Web Reactive帖子。
Maven POM
对于这篇文章,我正在使用嵌入式MongoDB。 我想与在内存中加载的实例进行对话,该实例具有与我的生产环境相同的功能,从而受益匪浅。 这使得开发和测试快速发展。
你可以在此处查看我的文章以在Spring Boot应用程序中配置和使用嵌入式MongoDB。
引入嵌入式MongoDB的依赖关系是:
12 3 de.flapdoodle.embed 4 5de.flapdoodle.embed.mongo 6 7runtime 8 9
Reactive MongoDB的全部功能取决于MongoDB驱动程序。 官方的MongoDB Reactive Streams Java驱动程序实现了Reactive Streams API,以与其他反应式流实现实现互操作性。 反应性驱动程序为MongoDB提供具有无阻塞背压的异步流处理。
要使用驱动程序,请添加此依赖项。
12 3 org.mongodb 4 5mongodb-driver-reactivestreams 6 71.5.0 8 9
这是完整的pom.xml:
12 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 5 4.0.0 6 78 9 16 17org.springframework.boot 10 11spring-boot-starter-parent 12 131.5.4.RELEASE 14 15spring-boot-reactive-mongodb 18 19SpringBoot Reactive MongoDB 20 2122 23 36 37Kay-M1 24 255.0.0.M3 26 273.0.3.RELEASE 28 291.5.0 30 31UTF-8 32 331.8 34 3538 39 94 9540 41 46 47org.springframework.boot 42 43spring-boot-starter 44 4548 49 54 55org.springframework.data 50 51spring-data-mongodb 52 5356 57 62 63io.projectreactor 58 59reactor-core 60 6164 65 72 73org.mongodb 66 67mongodb-driver-reactivestreams 68 69${mongodb-driver-reactivestreams.version} 70 7174 75 82 83de.flapdoodle.embed 76 77de.flapdoodle.embed.mongo 78 79runtime 80 8184 85 92 93org.springframework.boot 86 87spring-boot-starter-test 88 89test 90 9196 97 106 10798 99 104 105spring-libs-snapshot 100 101https://repo.spring.io/libs-snapshot 102 103108 109 118 119110 111 116 117spring-libs-snapshot 112 113https://repo.spring.io/libs-snapshot 114 115
域对象
我已经为这篇文章写了一个产品领域对象。 产品具有名称,描述,价格和产品URL。
1 Product.java: 2 3 package guru.springframework.domain; 4 5 import org.bson.types.ObjectId; 6 7 import org.springframework.data.annotation.Id; 8 9 import org.springframework.data.mongodb.core.mapping.Document; 10 11 import java.math.BigDecimal; 12 13 @Document 14 15 public class Product { 16 17 @Id 18 19 private ObjectId _id; 20 21 private String name; 22 23 private String description; 24 25 private BigDecimal price; 26 27 private String imageUrl; 28 29 public Product(String name, String description, BigDecimal price, String imageUrl) { 30 31 this.name = name; 32 33 this.description = description; 34 35 this.price = price; 36 37 this.imageUrl = imageUrl; 38 39 } 40 41 public ObjectId getId() { 42 43 return _id; 44 45 } 46 47 public void setId(ObjectId id) { 48 49 this._id = id; 50 51 } 52 53 public String getDescription() { 54 55 return description; 56 57 } 58 59 public void setDescription(String description) { 60 61 this.description = description; 62 63 } 64 65 public BigDecimal getPrice() { 66 67 return price; 68 69 } 70 71 public void setPrice(BigDecimal price) { 72 73 this.price = price; 74 75 } 76 77 public String getImageUrl() { 78 79 return imageUrl; 80 81 } 82 83 public void setImageUrl(String imageUrl) { 84 85 this.imageUrl = imageUrl; 86 87 } 88 89 }
Spring Data MongoDB反应式CRUD存储库
如果你在Spring Boot应用程序中使用过Spring Data,那么你将熟悉存储库模式。 你扩展了CrudRepository或其子接口,Spring Data MongoDB将为你生成实现。
反应性存储库以相同的方式工作。 你可以从ReactiveCrudRepository扩展存储库接口,指定特定于域的查询方法,并依靠Spring Data MongoDB提供实现。
ReactiveCrudRepository使用Spring Framework 5中引入的反应类型。它们是Mono和Flux,它们实现了反应流。
这是反应式存储库界面。
1 ReactiveProductRepository.java: 2 3 package guru.springframework.repositories; 4 5 import guru.springframework.domain.Product; 6 7 import reactor.core.publisher.Flux; 8 9 import reactor.core.publisher.Mono; 10 11 import org.springframework.data.mongodb.repository.Query; 12 13 import org.springframework.data.repository.reactive.ReactiveCrudRepository; 14 15 public interface ReactiveProductRepository extends ReactiveCrudRepository{ 16 17 Flux findByName(String name); 18 19 Flux findByName(Mono name); 20 21 Mono findByNameAndImageUrl(Mono name, String imageUrl); 22 23 @Query("{ 'name': ?0, 'imageUrl': ?1}") 24 25 Mono findByNameAndImageUrl(String name, String imageUrl); 26 27 }
如你所见,在此ReactiveProductRepository接口中,存储库使用反应类型作为返回类型。
Spring Data MongoDB中的反应性存储库也可以使用反应性类型作为参数。 重载的findByName()和findByNameAndImageUrl()方法就是这样的示例。
Spring Data MongoDB反应性存储库的配置
配置类类似于非反应性类。 除了一些基础设施设置之外,我们还有@EnableReactiveMongoRepositories批注,用于激活对反应式Spring Data的支持。
ApplicationConfiguration类的代码是这里。
1 ApplicationConfiguration.java: 2 3 package guru.springframework; 4 5 import org.springframework.boot.autoconfigure.AutoConfigureAfter; 6 7 import org.springframework.boot.autoconfigure.SpringBootApplication; 8 9 import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; 10 11 import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; 12 13 import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration; 14 15 import org.springframework.context.annotation.Bean; 16 17 import org.springframework.context.annotation.DependsOn; 18 19 import org.springframework.core.env.Environment; 20 21 import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration; 22 23 import org.springframework.data.mongodb.core.mapping.event.LoggingEventListener; 24 25 import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; 26 27 import com.mongodb.reactivestreams.client.MongoClient; 28 29 import com.mongodb.reactivestreams.client.MongoClients; 30 31 @SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) 32 33 @EnableReactiveMongoRepositories 34 35 @AutoConfigureAfter(EmbeddedMongoAutoConfiguration.class) 36 37 class ApplicationConfiguration extends AbstractReactiveMongoConfiguration { 38 39 private final Environment environment; 40 41 public ApplicationConfiguration(Environment environment) { 42 43 this.environment = environment; 44 45 } 46 47 @Override 48 49 @Bean 50 51 @DependsOn("embeddedMongoServer") 52 53 public MongoClient mongoClient() { 54 55 int port = environment.getProperty("local.mongo.port", Integer.class); 56 57 return MongoClients.create(String.format("mongodb://localhost:%d", port)); 58 59 } 60 61 @Override 62 63 protected String getDatabaseName() { 64 65 return "reactive-mongo"; 66 67 } 68 69 }
这个ApplicationConfiguration类扩展了AbstractReactiveMongoConfiguration,它是反应式Spring Data MongoDB配置的基类。 mongoClient()方法使用@Bean注释,以显式声明一个可配置的MongoClient bean,该bean代表MongoDB的连接池。
Spring Data MongoDB集成测试
让我们为存储库层编写一些集成测试,以验证我们的代码是否按预期使用了反应式MongoDB。
这是集成测试代码:
1 ReactiveProductRepositoryIntegrationTest.java: 2 3 package guru.springframework; 4 5 import static org.assertj.core.api.Assertions.*; 6 7 import guru.springframework.domain.Product; 8 9 import guru.springframework.repositories.ReactiveProductRepository; 10 11 import reactor.core.publisher.Flux; 12 13 import reactor.core.publisher.Mono; 14 15 import java.math.BigDecimal; 16 17 import java.util.List; 18 19 import org.junit.Before; 20 21 import org.junit.Test; 22 23 import org.junit.runner.RunWith; 24 25 import org.springframework.beans.factory.annotation.Autowired; 26 27 import org.springframework.boot.test.context.SpringBootTest; 28 29 import org.springframework.data.mongodb.core.CollectionOptions; 30 31 import org.springframework.data.mongodb.core.ReactiveMongoOperations; 32 33 import org.springframework.test.context.junit4.SpringRunner; 34 35 @RunWith(SpringRunner.class) 36 37 @SpringBootTest 38 39 public class ReactiveProductRepositoryIntegrationTest { 40 41 @Autowired 42 43 ReactiveProductRepository repository; 44 45 @Autowired 46 47 ReactiveMongoOperations operations; 48 49 @Before 50 51 public void setUp() { 52 53 operations.collectionExists(Product.class) 54 55 .flatMap(exists -> exists ? operations.dropCollection(Product.class) : Mono.just(exists)) 56 57 .flatMap(o -> operations.createCollection(Product.class, new CollectionOptions(1024 * 1024, 100, true))) 58 59 .then() 60 61 .block(); 62 63 repository 64 65 .save(Flux.just(new Product("T Shirt", "Spring Guru printed T Shirt", new BigDecimal(125), "tshirt1.png"), 66 67 new Product("T Shirt", "Spring Guru plain T Shirt", new BigDecimal(115), "tshirt2.png"), 68 69 new Product("Mug", "Spring Guru printed Mug", new BigDecimal(39), "mug1.png"), 70 71 new Product("Cap", "Spring Guru printed Cap", new BigDecimal(66), "cap1.png"))) 72 73 .then() 74 75 .block(); 76 77 } 78 79 @Test 80 81 public void findByNameAndImageUrlWithStringQueryTest() { 82 83 Product mug = repository.findByNameAndImageUrl("Mug", "mug1.png") 84 85 .block(); 86 87 assertThat(mug).isNotNull(); 88 89 } 90 91 @Test 92 93 public void findByNameAndImageUrlWithMonoQueryTest() { 94 95 Product cap = repository.findByNameAndImageUrl(Mono.just("Cap"), "cap1.png") 96 97 .block(); 98 99 assertThat(cap).isNotNull(); 100 101 } 102 103 @Test 104 105 public void findByNameWithStringQueryTest() { 106 107 ListtShirts = repository.findByName("T Shirt") 108 109 .collectList() 110 111 .block(); 112 113 assertThat(tShirts).hasSize(2); 114 115 } 116 117 @Test 118 119 public void findByNameWithMonoQueryTest() { 120 121 List tShirts = repository.findByName(Mono.just("T Shirt")) 122 123 .collectList() 124 125 .block(); 126 127 assertThat(tShirts).hasSize(2); 128 129 } 130 131 }
在测试类中,我们自动连接了两个Spring Bean。
Spring Data MongoDB提供的我们的ReactiveProductRepository实现和ReactiveMongoOperations实现。
ReactiveMongoOperations是主要的反应模板API类ReactiveMongoTemplate的接口。 该接口使用Project Reactor Mono和Flux反应类型定义了一组基本的反应数据访问操作。
ReactiveMongoOperations包含反应性对应项,可用于传统阻止模板API的MongoOperations接口中的大多数操作。
我们的集成测试的设置部分将删除所有现有文档并重新创建产品集合。 然后,安装方法将四个新文档插入到我们的MongoDB集合中。
我们正在调用.block()方法以确保在执行下一条命令之前完成处理。
这是IntelliJ集成测试的输出:
结论
文章写道这里,如有不足之处,欢迎补充评论。
抽丝剥茧,细说架构那些事!