В прошлом году я написал две статьи о JPA Criteria и Querydsl (см. статьи Введение и Метамодель). С конца прошлого года вышла новая крупная версия Spring Boot 3. Этот релиз основан на Spring Framework 6 с несколькими значительными изменениями и проблемами, которые следует учитывать при обновлении.
Цель этой статьи — выделить эти изменения при обновлении проекта sat-jpa (проект SAT). Используемые здесь технологии:
- Spring Boot 3.0.2,
- Hibernate 6.1.6.Final
- Spring Data JPA 3.0.1 и
- Querydsl 5.0.0.
Spring Framework 6.0.4
Spring Framework 6 имеет множество изменений (см. Что нового в Spring Framework 6.x), ключевые изменения:
- Переход на базовый уровень Java до Java 17 (по-прежнему последняя версия Java LTS на момент написания этой статьи) — то есть это минимальная версия Java, которую мы должны использовать.
- Переход на базовый уровень Jakarta до Jakarta EE 9+.
Помимо этого, в Spring MVC, используемом в проекте SAT, произошло лишь одно незначительное изменение.
Spring MVC 6.0.4
Все методы в классе ResponseEntityExceptionHandler
изменили свои сигнатуры. Аргумент status
был изменен с типа HttpStatus
на тип HttpStatusCode
(см. изменение в классе CityExceptionHandler).
HttpStatus в Spring MVC 5
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return buildResponse(BAD_REQUEST, exception);
}
HttpStatusCode в Spring MVC 6
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
HttpHeaders headers, HttpStatusCode status, WebRequest request) {
return buildResponse(BAD_REQUEST, exception);
}
Spring Boot 3.0.2
Spring Boot 3 содержит много изменений (см. Заметки о выпуске Spring Boot 3.0); наиболее важными являются эти:
- Java 17 (определяется Spring Framework).
-
Обновление до Spring Framework 6 (см. выше).
-
Увеличить до Hibernate 6 (см. ниже).
- Миграция от JavaEE к зависимостям Jakarta EE — это не важно в нашем случае, так как мы не полагаемся на enterprise Java, но это может повлиять на многие зависимости (например, servlet API, валидация, устойчивость, JMS и т. д.).
- Незначительные изменения в Spring MVC 6 в классе
ResponseEntityExceptionHandler
(см. следующую часть).
Начнем с простых изменений Jakarta EE. Таким образом, мы сможем сосредоточиться на устойчивости после этого.
Зависимости Jakarta EE
Значительным изменением является миграция от Java EE к зависимостям Jakarta EE. Spring Framework 6 установил базовый уровень как Jakarta EE 9 (см. Что нового в Spring Framework 6.x), но Spring Boot 3 уже использует Jakarta EE 10 (см. Заметки о выпуске Spring Boot 3.0) для многих API (например, Servlet или JPA — назовем некоторые технологии).
В результате, все классы, использующие другой класс из пакета jakarta
, должны перейти к тому же классу из пакета javax
(см., например, аннотации PostConstruct или Entity).
Импорты Javax
import javax.annotation.PostConstruct;
import javax.persistence.Entity;
Импорты Jakarta
import jakarta.annotation.PostConstruct;
import jakarta.persistence.Entity;
Hibernate 6.1.6
Еще одно значительное изменение в Spring Boot 3 – это обновление с Hibernate 5.6 до Hibernate 6.1. Подробности о Hibernate 6.1 можно найти здесь или в заметках о выпуске.
Честно говоря, я не обратил внимания на это изменение до тех пор, пока не пришлось исправить один не проходящий тест из-за разного размера результата (см. исправление в классе CountryRepositoryCustomTests
). Реализация с новым Hibernate 6 возвращает меньше сущностей, чем раньше.
Стоит упомянуть два изменения здесь, основанные на этом расследовании. Начнем с логирования.
Ведение журнала
Логгеры Hibernate были изменены с org.hibernate.type
на org.hibernate.orm.jdbc
(см. эту ссылку и эту ссылку).
Примечание: все доступные параметры конфигурации можно найти в классе org.hibernate.cfg.AvailableSettings
.
Hibernate 5
Был один логгер для скрытых и извлеченных значений.
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
Hibernate 6
Hibernate 6 изменил основную пакет и разделил их на два разных логгера для различения операции – какое значение следует логировать.
logging.level.org.hibernate.orm.jdbc.bind=trace
logging.level.org.hibernate.orm.jdbc.extract=trace
Семантическая модель запроса
После устранения проблем с ведением журнала было подтверждено, что Hibernate действительно извлекает два записи из БД:
2023-01-25T08:40:18.819+01:00 INFO 6192 --- [ main] c.g.a.s.j.c.CountryRepositoryCustomTests : Started CountryRepositoryCustomTests in 4.678 seconds (process running for 5.745)
Hibernate: select c2_0.id,c2_0.name from city c1_0 join country c2_0 on c2_0.id=c1_0.country_id where c1_0.name like ? escape '!' and c1_0.state like ? escape '!'
2023-01-25T08:40:19.221+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.222+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([2] : [VARCHAR]) - [USA]
2023-01-25T08:40:19.240+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.241+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([2] : [VARCHAR]) - [USA]
Однако тест получает только одну сущность от Hibernate, как видно на этих скриншотах отладки:
Изменение поведения вызвано новой Семантической моделью запроса с автоматическим удалением дубликатов (см. Семантическую модель запроса часть), введенной с Hibernate 6 (см. строку 178 в классе org.hibernate.sql.results.spi.ListResultsConsumer
). Теперь Hibernate 6 возвращает результат с удаленными дубликатами.
Генератор JPA Hibernate
Зависимость Hibernate Jpamodelgen Maven, управляемая Spring Boot Dependencies, была перенесена из пакета org.hibernate
в пакет org.hibernate.orm
. См.:
Spring Boot 2.7.5
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
Spring Boot 3.0.2
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
Liquibase
Для завершения основных зависимостей устойчивости, Liquibase был обновлен с версии 4.9.1 до 4.17.2. Значительных различий нет, за исключением использования зависимости JAX-B. Зависимость должна использовать JAX-B от Jakarta вместо Javax (см. следующую ссылку).
Spring Boot 2.7.5
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
Spring Boot 3.0.2
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<exclusions>
<exclusion> <!-- due to SB 3.0 switch to Jakarta -->
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
Spring Data JPA 3.0.1
Spring Boot 3.0.2 зависит от Spring Data Release Train 2022.0.1 (см. Заметки о выпуске Spring Data 2022.0 – Turing), где используется Spring Data JPA 3.0.1 с этими ключевыми изменениями (см. заметки о выпуске):
- Переключение базовой линии Java на Java 17,
- Переключение базовой линии Jakarta на Jakarta EE 10 и
- Поднятие до Hibernate 6
Примечание: ранее используемая версия (в нашем случае) была 2.7.5.
Querydsl 5.0.0
Версия Querydsl не изменилась, но она подверглась влиянию аналогичному тому, что было у Liquibase. Зависимости теперь должны использоваться от Jakarta вместо Javax. Следовательно, зависимость Querydsl должна использовать классификатор jakarta
вместо старого классификатора jpa
(см. это ссылка).
Spring Boot 2.7.5
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<classifier>jpa</classifier>
<scope>provided</scope>
</dependency>
Spring Boot 3.0.2
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
<version>${querydsl.version}</version>
<classifier>jakarta</classifier>
</dependency>
Заключение
В данной статье рассматривается обновление до последней версии Spring Boot 3.0.2 для JPA и Querydsl (на момент написания статьи). Статья началась с изменений в Spring Framework и Spring Boot. Далее были рассмотрены все изменения в Hibernate и связанных технологиях. В конце упомянуты незначительные изменения, связанные с Spring Data 3.0.1 и Querydsl 5.0.0.
Полный исходный код, продемонстрированный выше, доступен в моем GitHub репозитории.
Примечание: также существует предыдущая статья, Руководство по обновлению до Spring Data Elasticsearch 5.0, посвященная аналогичному обновлению Elasticsearch с использованием Spring Boot 3.
Source:
https://dzone.com/articles/upgrade-guide-to-spring-boot-3-for-spring-data-jpa-3-and-querydsl-5