Аннотация @EntityListeners
Аннотация @EntityListeners является частью спецификации JPA (Jakarta Persistence API) и позволяет привязать кастомные слушатели (listeners) к сущностям JPA.
Эти слушатели могут перехватывать события жизненного цикла сущности, такие как:
@PrePersist (перед сохранением)
@PostPersist (после сохранения)
@PreUpdate (перед обновлением)
@PostUpdate (после обновлением)
@PreRemove (перед удалением)
@PostRemove (после удалением)
@PostLoad (после загрузкой из БД)
Аннотация находится в пакете jakarta.persistence и применяется на уровне класса сущности.
Параметры аннотации
value (обязательный)
Тип: Массив классов (Class<?>[])
Описание: Принимает один или несколько классов-слушателей, которые должны реализовывать callback-методы JPA.
Пример:
Жизненный цикл слушателей
Регистрация слушателей
При загрузке метаданных JPA провайдер (Hibernate) регистрирует указанные классы-слушатели для сущности.
Вызов callback-методов
При наступлении соответствующего события жизненного цикла JPA вызывает методы слушателей в порядке их объявления.
Порядок выполнения
Если для сущности определено несколько слушателей, их методы выполняются в порядке объявления в аннотации.
Глобальные слушатели (зарегистрированные в orm.xml) выполняются после локальных.
Механизмы работы в Spring
1. Интеграция с Spring
Spring автоматически поддерживает DI в JPA Entity Listeners, если они являются Spring-бинами.
Для этого нужно:
Пометить класс-слушатель как @Component
Зарегистрировать его в Spring-контексте
2. Пример Spring-совместимого слушателя
3. Конфигурация в Spring Boot
Spring Boot автоматически настраивает поддержку Entity Listeners через:
Автоконфигурацию JPA (HibernateJpaAutoConfiguration)
Поддержку инъекции зависимостей в слушатели
Варианты использования
1. Аудит изменений
2. Валидация перед сохранением
3. Кеширование
Ограничения и особенности
Контекст выполнения
Callback-методы выполняются в том же контексте транзакции, что и основная операция.
Исключения
Выброс исключения в callback-методе приводит к откату транзакции.
Порядок выполнения
Методы выполняются в порядке:
Callback-методы самой сущности
Локальные @EntityListeners
Глобальные слушатели
DI ограничения
В чистом JPA слушатели не поддерживают инъекцию зависимостей
В Spring DI работает только для Spring-бинов
#Java #Training #Hard #Spring #SpringDataJPA #EntityListeners
Аннотация @EntityListeners является частью спецификации JPA (Jakarta Persistence API) и позволяет привязать кастомные слушатели (listeners) к сущностям JPA.
Эти слушатели могут перехватывать события жизненного цикла сущности, такие как:
@PrePersist (перед сохранением)
@PostPersist (после сохранения)
@PreUpdate (перед обновлением)
@PostUpdate (после обновлением)
@PreRemove (перед удалением)
@PostRemove (после удалением)
@PostLoad (после загрузкой из БД)
Аннотация находится в пакете jakarta.persistence и применяется на уровне класса сущности.
Параметры аннотации
value (обязательный)
Тип: Массив классов (Class<?>[])
Описание: Принимает один или несколько классов-слушателей, которые должны реализовывать callback-методы JPA.
Пример:
@Entity
@EntityListeners({AuditListener.class, CacheInvalidationListener.class})
public class User {
// поля сущности
}
Жизненный цикл слушателей
Регистрация слушателей
При загрузке метаданных JPA провайдер (Hibernate) регистрирует указанные классы-слушатели для сущности.
Вызов callback-методов
При наступлении соответствующего события жизненного цикла JPA вызывает методы слушателей в порядке их объявления.
Порядок выполнения
Если для сущности определено несколько слушателей, их методы выполняются в порядке объявления в аннотации.
Глобальные слушатели (зарегистрированные в orm.xml) выполняются после локальных.
Механизмы работы в Spring
1. Интеграция с Spring
Spring автоматически поддерживает DI в JPA Entity Listeners, если они являются Spring-бинами.
Для этого нужно:
Пометить класс-слушатель как @Component
Зарегистрировать его в Spring-контексте
2. Пример Spring-совместимого слушателя
@Component
public class AuditListener {
@PrePersist
public void prePersist(Object entity) {
System.out.println("PrePersist: " + entity);
}
@PreUpdate
public void preUpdate(Object entity) {
System.out.println("PreUpdate: " + entity);
}
}
3. Конфигурация в Spring Boot
Spring Boot автоматически настраивает поддержку Entity Listeners через:
Автоконфигурацию JPA (HibernateJpaAutoConfiguration)
Поддержку инъекции зависимостей в слушатели
Варианты использования
1. Аудит изменений
public class AuditListener {
@PrePersist
public void setCreationDate(Object entity) {
if (entity instanceof Auditable) {
((Auditable) entity).setCreatedAt(LocalDateTime.now());
}
}
}
2. Валидация перед сохранением
public class ValidationListener {
@PrePersist
@PreUpdate
public void validate(Object entity) {
if (entity instanceof Validatable) {
((Validatable) entity).validate();
}
}
}
3. Кеширование
public class CacheListener {
@PostPersist
@PostUpdate
@PostRemove
public void invalidateCache(Object entity) {
CacheManager.evict(entity.getClass(), entity.getId());
}
}
Ограничения и особенности
Контекст выполнения
Callback-методы выполняются в том же контексте транзакции, что и основная операция.
Исключения
Выброс исключения в callback-методе приводит к откату транзакции.
Порядок выполнения
Методы выполняются в порядке:
Callback-методы самой сущности
Локальные @EntityListeners
Глобальные слушатели
DI ограничения
В чистом JPA слушатели не поддерживают инъекцию зависимостей
В Spring DI работает только для Spring-бинов
#Java #Training #Hard #Spring #SpringDataJPA #EntityListeners
Аннотация @Projection
Аннотация @Projection используется в Spring Data для определения проекций - специальных интерфейсов или классов, которые позволяют выбирать только определенные поля из сущностей.
Это полезно для:
Оптимизации запросов (избегания select *)
Создания DTO на лету
Кастомизации JSON-представления REST API
Проекции находятся в пакете org.springframework.data.rest.core.config.Projection и применяются к интерфейсам или классам.
Параметры аннотации
types (обязательный)
Тип: Class<?>[]
Описание: Указывает сущности, к которым применяется проекция
Пример:
name (необязательный)
Тип: String
Описание: Задает имя проекции для использования в Spring Data REST
Пример:
Типы проекций
1. Интерфейсные проекции
Наиболее распространенный подход:
2. Классовые проекции (DTO)
Используются классы вместо интерфейсов:
3. Динамические проекции
Можно создавать проекции на лету через SpEL:
Жизненный цикл проекций
Объявление проекции
Создается интерфейс/класс с аннотацией @Projection
Определяются методы, соответствующие полям сущности
Использование в репозитории
Spring Data создает прокси-реализацию при выполнении запроса
Преобразование результатов
После выполнения запроса результаты маппятся на проекцию
Механизмы Spring Data
1. Автоматический маппинг
Spring Data автоматически:
Анализирует методы проекции
Создает соответствующий SQL (только выбранные поля)
Преобразует результат в проекцию
2. Интеграция с репозиториями
3. Поддержка в Spring Data REST
Проекции можно активировать через параметр запроса:
Примеры использования
1. Базовый пример
2. Комплексная проекция
3. Вложенные проекции
Настройки Spring Boot
Автоконфигурация
Spring Boot автоматически настраивает поддержку проекций через SpringDataWebConfiguration
Ручная регистрация
Можно явно зарегистрировать проекции:
Настройка REST
В application.properties:
#Java #Training #Hard #Spring #SpringDataJPA #Projection
Аннотация @Projection используется в Spring Data для определения проекций - специальных интерфейсов или классов, которые позволяют выбирать только определенные поля из сущностей.
Это полезно для:
Оптимизации запросов (избегания select *)
Создания DTO на лету
Кастомизации JSON-представления REST API
Проекции находятся в пакете org.springframework.data.rest.core.config.Projection и применяются к интерфейсам или классам.
Параметры аннотации
types (обязательный)
Тип: Class<?>[]
Описание: Указывает сущности, к которым применяется проекция
Пример:
@Projection(types = {User.class})
public interface UserSummary {
String getUsername();
String getEmail();
}
name (необязательный)
Тип: String
Описание: Задает имя проекции для использования в Spring Data REST
Пример:
@Projection(name = "summary", types = User.class)
public interface UserSummary {...}
Типы проекций
1. Интерфейсные проекции
Наиболее распространенный подход:
@Projection(types = User.class)
public interface UserView {
String getUsername();
String getEmail();
// Можно включать связанные сущности
@Value("#{target.department.name}")
String getDepartmentName();
}
2. Классовые проекции (DTO)
Используются классы вместо интерфейсов:
@Projection(types = User.class)
public class UserDto {
private final String username;
private final String email;
public UserDto(String username, String email) {
this.username = username;
this.email = email;
}
// Геттеры
}
3. Динамические проекции
Можно создавать проекции на лету через SpEL:
@Projection(types = User.class)
public interface DynamicUserView {
@Value("#{target.username + ' (' + target.email + ')'}")
String getDisplayName();
}
Жизненный цикл проекций
Объявление проекции
Создается интерфейс/класс с аннотацией @Projection
Определяются методы, соответствующие полям сущности
Использование в репозитории
Spring Data создает прокси-реализацию при выполнении запроса
Преобразование результатов
После выполнения запроса результаты маппятся на проекцию
Механизмы Spring Data
1. Автоматический маппинг
Spring Data автоматически:
Анализирует методы проекции
Создает соответствующий SQL (только выбранные поля)
Преобразует результат в проекцию
2. Интеграция с репозиториями
public interface UserRepository extends JpaRepository<User, Long> {
<T> List<T> findBy(Class<T> type);
UserSummary findSummaryById(Long id);
}
3. Поддержка в Spring Data REST
Проекции можно активировать через параметр запроса:
GET /users/1?projection=summary
Примеры использования
1. Базовый пример
@Entity
public class User {
private Long id;
private String username;
private String email;
// геттеры/сеттеры
}
@Projection(types = User.class)
public interface UserSummary {
String getUsername();
String getEmail();
}
// В репозитории
UserSummary findSummaryById(Long id);
2. Комплексная проекция
@Projection(types = {User.class, Department.class})
public interface UserDetailView {
String getUsername();
@Value("#{target.department.name}")
String getDepartmentName();
default String getDisplayInfo() {
return getUsername() + " from " + getDepartmentName();
}
}
3. Вложенные проекции
@Projection(types = Order.class)
public interface OrderView {
String getOrderNumber();
@Value("#{target.customer}")
CustomerView getCustomer();
}
@Projection(types = Customer.class)
public interface CustomerView {
String getName();
}
Настройки Spring Boot
Автоконфигурация
Spring Boot автоматически настраивает поддержку проекций через SpringDataWebConfiguration
Ручная регистрация
Можно явно зарегистрировать проекции:
@Configuration
public class ProjectionConfig {
@Bean
public ProjectionDefinitionRegistrar projectionRegistrar() {
return registrar -> {
registrar.addProjection(UserSummary.class);
};
}
}
Настройка REST
В application.properties:
spring.data.rest.default-projection=summary
#Java #Training #Hard #Spring #SpringDataJPA #Projection