走在前沿
VMware 提供培训和认证,以加速您的进步。
了解更多Spring Data 发布版 Evans 已经发布一段时间了,现在是时候向大家介绍我们在这个版本中提供的最新和最棒的功能了。
需要介绍的内容很多,因为 commons 模块有了重大改进。这些更改已经应用到一些存储模块中,并且随着时间的推移,也将逐渐应用到其他模块中。所有这些更改至少在 Spring Data JPA 中都已可用。话不多说,让我们直接开始吧。
Java 8 已经发布有一段时间了,之前的 Spring Data 发布版已经为其中的一些功能添加了基本支持。在 Evans 发布版中,我们显著扩展了对 Java 8 的支持。
自 Dijkstra 发布版 以来,Java 8 的 Optional
就一直是支持的返回类型,这使得您无需在代码中到处散布 null
检查。当用作存储库的返回类型时,我们只需为您包装和解包值。
从 Evans 发布版开始,可以在存储库接口中使用 默认方法,例如将传递给方法的部分参数转发到其他查询方法。
interface PersonRepository extends Repository<Person, Long> {
Optional<Customer> findByLastname(String lastname);
default Optional<Customer> findByLastname(Customer customer) {
return findByLastname(customer == null ? null : customer.getLastname());
}
}
配置应用程序以使用不同的 Spring Data 模块一直以来都存在一些问题。例如,您可能希望将 JPA 和 MongoDB 结合使用,其中 Customer
恰好是一个 JPA 实体,而 Order
是一个 MongoDB 文档,两者都通过相应的存储库接口持久化。
@Entity
class Customer {
@Id @GeneratedValue Long id;
String firstname, lastname;
// ...
}
@Document
class Order {
@Id String id;
Long customerId;
Date orderDate;
// ...
}
interface CustomerRepository extends CrudRepository<Customer, Long> {}
interface OrderRepository extends CrudRepository<Order, String> {}
在 Spring Data Evans 发布版之前,您必须手动配置 MongoDB 和 JPA 的存储库设置,以便相互排除与给定存储无关的接口。用户通常为此使用单独的包。
现在,存储库设置检测到类路径上存在多个 Spring Data 模块,并自动限制存储库扫描,并检查给定存储库使用的域类型以查找特定于存储的注释,例如 @Entity
和 @Document
,以确定它们所属的具体实现。例如,Spring Data MongoDB 模块将丢弃(意外)检测到的 CustomerRepository
,因为我们没有找到 @Document
注释。
动态限制结果并不是什么新概念,因为 Spring Data 从一开始就将 Pagable
作为抽象,我相信几乎每个 Spring Data 用户都熟悉类似的东西。
List<Person> findByLastname(String lastname, Pageable page)
此方法声明提供了相当大的灵活性:客户端定义他们想要访问的元素的页码、大小和排序顺序。如果这些值动态更改(例如,当您逐页遍历结果集时),这将非常有用。
但是,如果您始终只对例如前 10 个结果感兴趣,并且始终希望它们按姓氏排序呢?这可以通过静态定义一个 PageRequest
并将其重用于每次方法调用来实现。但是,这仍然要求客户端传入特殊的 PageRequest
。
从 Spring Data Evans 开始,我们现在为您提供了一种方便的方法来明确将结果集限制为一定数量的元素,方法是使用关键字 top
和 first
,后跟一个可选的正数值(默认为 1)。
List<Person> findTop10ByLastnameOrderByFirstnameDesc(String lastname);
Evans RC1 发布版为 MongoDB 2.6 引入了基本的 文本索引支持。使用 @TextIndexed
可以标记您希望启用文本搜索的属性,以便我们可以继续为您创建索引。请注意,在引用复杂类型的属性上放置 @TextIndexed
将会索引该类型的所有属性。由于评分是全文搜索的基本部分,因此 @TextScore
注释将断言任何全文查询都返回文档评分,允许您按相关性对它们进行排序。
@Document
class BlogPost {
@Id String id;
@TextIndexed(weight = 3) String title;
@TextIndexed(weight = 2) String content;
@TextIndexed List<String> categories;
@TextScore Float score;
}
有了这些,我们扩展了存储库支持以接受 TextCriteria
实例,该实例将定义有关要执行的文本搜索的详细选项:要搜索的术语、语言选项等。
interface BlogPostRepository extends CrudRepository<BlogPost, String> {
Page<BlogPost> findBy(TextCriteria criteria, Pageable page);
List<BlogPost> findAllByOrderByScoreDesc(TextCriteria criteria);
}
第一个查询方法非常简单。它执行给定的 TextCriteria
并分页结果。第二个查询方法定义将给定的 TextCriteria
与从方法名称派生的标准条件定义相结合。这表明您可以轻松地将文本搜索与标准查询结合使用。
我们添加了 @Meta
,允许您定义查询的输出和行为。例如,通过设置 maxExecutionTime
,可以定义查询允许花费的最长时间(以毫秒为单位)。任何超过限制的执行都将导致错误。您还可以建议 MongoDB 只扫描最多数量的文档并返回找到的内容,直到达到限制为止,方法是设置 maxScanDocuments
,而 comment
允许您定义可以在 system.profile
集合中搜索的文本,以防您为 MongoDB 实例启用了分析功能。
@Meta(maxExcecutionTime = 100, comment = "onlyLimitedTime")
List<Customer> findByFirstname(String firstname);
Redis 2.8 引入了称为 哨兵 的高可用性支持。Spring Data Evans 的 Redis 模块添加了对轻松配置连接到哨兵设置的支持,以便您的客户端能够在 Redis 集群中重新选举主节点时继续工作。
RedisSentinelConfiguration
定义了哨兵的位置,以便 ConnectionFactory
可以相应地设置池。对于 Jedis,它将为自动故障转移创建一个 JedisSentinelPool
。这意味着,如果您的主节点宕机,一旦哨兵同意新的主节点,您将收到与新主节点的连接,而无需任何进一步的交互。
@Configuration
class RedisSentinelApplicationConfig {
@Bean
RedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory(sentinelConfig());
}
@Bean
RedisSentinelConfiguration sentinelConfig() {
return new RedisSentinelConfiguration().master("mymaster")
.sentinel("localhost", 26379)
.sentinel("localhost", 26380)
.sentinel("localhost", 26381);
}
}
即将推出的 Spring Boot 1.2 将更进一步,如果存在 RedisSentinelConfiguration
,则会自动获取它并相应地初始化 RedisConnectionFactory
。
尽管 Solr 模式 API 尚未完成,但我们已经尝试尽可能多地支持它。在 Evans 发布版中,您现在可以动态地将缺失的字段添加到现有的(已管理的)模式中。为此,我们读取现有的字段定义并将其与从域类型的属性派生的字段定义进行比较。为此,我们扩展了 @Indexed
注释。它现在允许对要创建的字段进行一些微调,因为可以明确定义诸如 indexed
、stored
和 solrType
之类的值。
@Configuration
@EnableSolrRepositories(schemaCreationSupport = true)
class SolrConfiguration {
@Bean
SolrServer solrServer() {
return new HttpSolrServer("https://127.0.0.1:8983/solr");
}
}
@SolrDocument(solrCoreName = "collection1")
class ManagedProduct {
@Id String id;
@Indexed(type = "text_general") String name;
@Indexed(name = "cat") List<String> category;
}
一如既往,我们渴望听到您的反馈!请通过 Twitter、Stackoverflow 或 JIRA 与我们联系,以请求新功能、建议改进或报告错误。