Ответ
Specification — это паттерн из Domain-Driven Design (DDD), реализованный в Spring Data JPA (через модуль JpaSpecificationExecutor). Он позволяет инкапсулировать критерии выборки данных в объекты, что делает построение динамических, сложных запросов типобезопасным и удобным для повторного использования.
Для чего это нужно? Вместо создания множества методов репозитория (findByAAndB, findByCOrD) или использования @Query с условным сбором строки запроса, вы создаете отдельные объекты Specification<T>, которые затем комбинируете.
Основные компоненты:
- Интерфейс
JpaSpecificationExecutor<T>, который добавляется к вашему репозиторию. Он предоставляет методы типаfindAll(Specification<T> spec). - Класс
Specifications(в более старых версиях) или статические методы классаSpecification(в новых) для построения и комбинирования спецификаций.
Пример:
Допустим, есть сущность Customer.
// 1. Репозиторий с поддержкой Specification
public interface CustomerRepository extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
}
// 2. Создание спецификаций (обычно в отдельном классе)
public class CustomerSpecs {
public static Specification<Customer> hasName(String name) {
return (root, query, cb) -> name == null ? null : cb.equal(root.get("name"), name);
}
public static Specification<Customer> isActive() {
return (root, query, cb) -> cb.isTrue(root.get("active"));
}
}
// 3. Использование в сервисе
@Service
public class CustomerService {
@Autowired
private CustomerRepository repository;
public List<Customer> findActiveCustomersByName(String name) {
Specification<Customer> spec = Specification.where(CustomerSpecs.isActive())
.and(CustomerSpecs.hasName(name));
return repository.findAll(spec);
}
}
Почему это полезно: Спецификации делают код запросов более модульным, тестируемым и избегают проблемы "раздутого" репозитория. Они особенно эффективны для динамических фильтров в API поиска.