
9.5.1. Java 配置
使用 Java 配置类上的特定于存储的注释来定义存储库激活的配置。 有关 Spring 容器的基于 Java 的配置的介绍,请参阅Spring 参考文档中的 JavaConfig。@EnableJpaRepositories
启用 Spring 数据存储库的示例配置类似于以下内容:
例 35。基于注释的存储库配置示例
@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {
@Bean
EntityManagerFactory entityManagerFactory() {
// …
}
}
前面的示例使用特定于 JPA 的注释,您将根据实际使用的存储模块对其进行更改。这同样适用于thebean的定义。请参阅涵盖特定于商店的配置的部分。EntityManagerFactory
|
9.5.2.XML 配置
每个 Spring 数据模块都包含一个元素,该元素允许您定义 Spring 为您扫描的基本包,如以下示例所示:repositories
例 36。通过XML启用Spring 数据存储库
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="com.acme.repositories" />
</beans:beans>
在前面的示例中,指示 Spring 扫描其所有子包以查找接口扩展或其子接口之一。 对于找到的每个接口,基础结构都会注册特定于持久性技术,以创建处理查询方法调用的相应代理。 每个 Bean 都注册在从接口名称派生的 Bean 名称下,因此将注册一个接口。 嵌套存储库接口的 Bean 名称以其封闭类型名称为前缀。 基本包属性允许通配符,以便您可以定义扫描包的模式。com.acme.repositories
Repository
FactoryBean
UserRepository
userRepository
9.5.3. 使用过滤器
缺省情况下,基础结构选取扩展位于配置的基础包下的特定于持久性技术的子接口的每个接口,并为其创建一个 Bean 实例。 但是,您可能希望更精细地控制哪些接口为其创建了 Bean 实例。 为此,请在存储库声明中使用过滤器元素。 语义与 Spring 组件过滤器中的元素完全相同。 有关详细信息,请参阅这些元素的Spring 参考文档。Repository
例如,要从实例化中排除某些接口作为存储库 Bean,您可以使用以下配置:
例 37。使用过滤器
清单 18.爪哇岛
清单 19..XML
@Configuration
@EnableJpaRepositories(basePackages = "com.acme.repositories",
includeFilters = { @Filter(type = FilterType.REGEX, pattern = ".*SomeRepository") },
excludeFilters = { @Filter(type = FilterType.REGEX, pattern = ".*SomeOtherRepository") })
class ApplicationConfiguration {
@Bean
EntityManagerFactory entityManagerFactory() {
// …
}
}
前面的示例排除了以实例化结尾的所有接口,并包括以 结尾的接口。SomeRepository
SomeOtherRepository
9.5.4. 独立使用
您还可以在 Spring 容器之外使用存储库基础架构,例如,在 CDI 环境中。你的类路径中仍然需要一些 Spring 库,但通常,你也可以以编程方式设置存储库。提供存储库支持的 Spring 数据模块附带了您可以使用的特定于持久性技术的模块,如下所示:RepositoryFactory
例 38。存储库工厂的独立使用
RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);
9.6. Spring 数据存储库的自定义实现
Spring Data 提供了各种选项来创建查询方法,只需很少的编码。 但是,当这些选项不符合您的需求时,您还可以为存储库方法提供自己的自定义实现。 本节介绍如何执行此操作。
9.6.1. 自定义单个仓库
要使用自定义功能丰富存储库,您必须首先定义片段接口和自定义功能的实现,如下所示:
例 39。自定义存储库功能的界面
interface CustomizedUserRepository {
void someCustomMethod(User user);
}
例 40。实现自定义存储库功能
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
与片段接口对应的类名中最重要的部分是后缀。Impl
|
实现本身不依赖于 Spring 数据,可以是常规的 Spring bean。 因此,您可以使用标准的依赖注入行为来注入对其他 Bean 的引用(例如 a)、参与方面等。JdbcTemplate
然后,您可以让存储库接口扩展片段接口,如下所示:
例 41。对存储库界面的更改
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {
// Declare query methods here
}
使用存储库接口扩展片段接口结合了 CRUD 和自定义功能,并使其可供客户端使用。
Spring 数据存储库是通过使用形成存储库组合的片段来实现的。 片段是基本存储库、功能方面(如QueryDsl)和自定义接口及其实现。 每次向存储库界面添加接口时,都会通过添加片段来增强组合。 基本存储库和存储库方面实现由每个 Spring 数据模块提供。
以下示例显示了自定义接口及其实现:
例 42。片段及其实现
interface HumanRepository {
void someHumanMethod(User user);
}
class HumanRepositoryImpl implements HumanRepository {
public void someHumanMethod(User user) {
// Your custom implementation
}
}
interface ContactRepository {
void someContactMethod(User user);
User anotherContactMethod(User user);
}
class ContactRepositoryImpl implements ContactRepository {
public void someContactMethod(User user) {
// Your custom implementation
}
public User anotherContactMethod(User user) {
// Your custom implementation
}
}
以下示例显示了扩展的自定义存储库的接口:CrudRepository
例 43。对存储库界面的更改
interface UserRepository extends CrudRepository<User, Long>, HumanRepository, ContactRepository {
// Declare query methods here
}
存储库可以由多个自定义实现组成,这些实现按其声明顺序导入。 自定义实现的优先级高于基本实现和存储库方面。 此排序允许您覆盖基本存储库和方面方法,并在两个片段提供相同的方法签名时解决歧义。 存储库片段不限于在单个存储库界面中使用。 多个存储库可以使用片段界面,允许您跨不同存储库重用自定义项。
以下示例显示了存储库片段及其实现:
例 44。片段覆盖save(…)
interface CustomizedSave {
S save(S entity);
}
class CustomizedSaveImpl implements CustomizedSave {
public S save(S entity) {
// Your custom implementation
}
}
以下示例显示了使用上述存储库片段的存储库:
例 45。自定义存储库接口
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave {
}
interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave {
}
配置
存储库基础结构尝试通过扫描找到存储库的包下的类来自动检测自定义实现片段。 这些类需要遵循附加默认后缀的命名约定。Impl
以下示例显示了一个使用默认后缀的存储库和一个为后缀设置自定义值的存储库:
例 46。配置示例
清单 20.爪哇岛
清单 21..XML
@EnableJpaRepositories(repositoryImplementationPostfix = "MyPostfix")
class Configuration { … }
前面示例中的第一个配置尝试查找调用充当自定义存储库实现的类。 第二个示例尝试查找。com.acme.repository.CustomizedUserRepositoryImpl
com.acme.repository.CustomizedUserRepositoryMyPostfix
歧义的解决
如果在不同的包中找到具有匹配类名的多个实现,Spring Data 将使用 bean 名称来标识要使用的实现。
给定前面所示的以下两个自定义实现,将使用第一个实现。 它的 Bean 名称是,与片段接口 () 加上后缀的名称相匹配。CustomizedUserRepository
customizedUserRepositoryImpl
CustomizedUserRepository
Impl
例 47。解决不明确的实现
package com.acme.impl.one;
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
// Your custom implementation
}
package com.acme.impl.two;
@Component("specialCustomImpl")
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
// Your custom implementation
}
如果您注释接口,则 bean 名称 plusthen 与为存储库实现定义的名称匹配,并且使用它代替第一个。UserRepository
@Component("specialCustom")
Impl
com.acme.impl.two
手动接线
如果您的自定义实现仅使用基于注释的配置和自动连线,则上述方法效果很好,因为它被视为任何其他 Spring Bean。 如果您的实现片段 Bean 需要特殊连接,则可以声明 Bean 并根据上一节中描述的约定对其进行命名。 然后,基础结构按名称引用手动定义的 Bean 定义,而不是自己创建一个。 以下示例演示如何手动连接自定义实现:
例 48。自定义实现的手动接线
清单 22.爪哇岛
清单 23..XML
class MyClass {
MyClass(@Qualifier("userRepositoryImpl") UserRepository userRepository) {
…
}
}
9.6.2. 自定义基础仓库
当您想要自定义基本存储库行为以使所有存储库都受到影响时,上一节中描述的方法需要自定义每个存储库接口。 要改为更改所有存储库的行为,您可以创建一个实现来扩展特定于持久性技术的存储库基类。 然后,此类充当存储库代理的自定义基类,如以下示例所示:
例 49。自定义存储库基类
class MyRepositoryImpl<T, ID>
extends SimpleJpaRepository<T, ID> {
private final EntityManager entityManager;
MyRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
// Keep the EntityManager around to used from the newly introduced methods.
this.entityManager = entityManager;
}
@Transactional
public S save(S entity) {
// implementation goes here
}
}
|
该类需要具有特定于存储的存储库工厂实现使用的超类的构造函数。 如果存储库基类有多个构造函数,请覆盖采用存储特定基础结构对象(例如模板类)的构造函数。EntityInformation EntityManager
|
最后一步是使 Spring 数据基础架构知道自定义的存储库基类。 在配置中,可以使用 来执行此操作,如以下示例所示:repositoryBaseClass
例 50。配置自定义存储库基类
清单 24.爪哇岛
清单 25..XML
@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }
9.7. 从聚合根发布事件
存储库管理的实体是聚合根。 在域驱动设计应用程序中,这些聚合根通常发布域事件。 Spring Data 提供了一个注释,称为您可以在聚合根的方法上使用该注释,以使该发布尽可能简单,如以下示例所示:@DomainEvents
例 51。从聚合根公开域事件
class AnAggregateRoot {
@DomainEvents
Collection<Object> domainEvents() {
// … return events you want to get published here
}
@AfterDomainEventPublication
void callbackMethod() {
// … potentially clean up domain events list
}
}