Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
А что, выглядит надежно😱😜

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Аннотация @EnableJpaAuditing

Аннотация @EnableJpaAuditing активирует поддержку аудита сущностей JPA в Spring Data. Она позволяет автоматически отслеживать изменения в сущностях, такие как:
Кто создал или изменил запись (createdBy, lastModifiedBy).
Когда запись была создана или изменена (createdDate, lastModifiedDate).


Параметры аннотации

auditorAwareRef (необязательный)
Тип: String
Описание: Указывает имя бина, реализующего интерфейс AuditorAware<T>. Этот бин предоставляет информацию о текущем пользователе (например, из Spring Security).


Пример:
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
@Configuration
public class JpaConfig {
@Bean
public AuditorAware<String> auditorProvider() {
return () -> Optional.of("admin"); // Возвращает текущего пользователя
}
}


dateTimeProviderRef (необязательный)
Тип: String
Описание: Указывает имя бина, реализующего DateTimeProvider. Позволяет кастомизировать логику получения текущей даты/времени (например, для тестов).


Пример:
@EnableJpaAuditing(dateTimeProviderRef = "customDateTimeProvider")
@Configuration
public class JpaConfig {
@Bean
public DateTimeProvider customDateTimeProvider() {
return () -> Optional.of(Instant.now());
}
}


setDates (необязательный)
Тип: boolean
Значение по умолчанию: true

Описание: Если false, автоматическое обновление полей createdDate и lastModifiedDate отключается.

modifyOnCreate (необязательный)
Тип: boolean
Значение по умолчанию: true
Описание: Если false, поле lastModifiedDate не обновляется при создании сущности (только createdDate).


Жизненный цикл аудита

Инициализация
При старте приложения Spring ищет классы с @EnableJpaAuditing и регистрирует AuditingEntityListener.
Если указан auditorAwareRef, Spring внедряет соответствующий бин.


Сохранение/обновление сущности

Перед вставкой (@PrePersist) автоматически заполняются:
createdBy и createdDate (если поддерживается).

Перед обновлением (@PreUpdate) заполняются:
lastModifiedBy и lastModifiedDate.

Уничтожение
Аудит не влияет на удаление сущностей, но можно добавить @PreRemove логику вручную.

Механизмы Spring и настройки Spring Boot

1. Как работает аудит в Spring Data JPA?

AuditingEntityListener – JPA-колбек, который обрабатывает события @PrePersist и @PreUpdate.
AuditorAware – интерфейс для получения информации о текущем пользователе.
@CreatedDate, @LastModifiedDate, @CreatedBy, @LastModifiedBy – аннотации для полей сущности.

2. Настройка сущности
@Entity
@EntityListeners(AuditingEntityListener.class) // Включение аудита
public class User {
@Id
@GeneratedValue
private Long id;

@CreatedDate
private Instant createdDate;

@LastModifiedDate
private Instant lastModifiedDate;

@CreatedBy
private String createdBy;

@LastModifiedBy
private String lastModifiedBy;
}


3. Конфигурация Spring Boot

Если используется Spring Boot, можно не указывать
@EnableJpaAuditing вручную, если:
Есть бин AuditorAware.
Включен spring.data.jpa.repositories.bootstrap-mode=default (по умолчанию).


Пример application.properties:
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true


4. Интеграция с Spring Security

Если приложение использует Spring Security, AuditorAware может возвращать текущего пользователя:
@Bean
public AuditorAware<String> auditorAware() {
return () -> Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.map(Authentication::getName);
}


Варианты настройки

Отключение аудита для отдельных полей
Не аннотировать поле @CreatedBy, если оно не нужно.

Кастомные даты
Реализовать DateTimeProvider, если требуется использовать не Instant.now(), а другую временную зону.

Аудит без Spring Security
Можно возвращать фиксированное значение (например, "system"):

@Bean
public AuditorAware<String> auditorAware() {
return () -> Optional.of("system");
}


#Java #Training #Hard #Spring #SpringDataJPA #EnableJpaAuditing
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Аннотация @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
Что выведет код?

import java.util.function.Function;

public class Task030425 {
public static void main(String[] args) {
Function<Integer, Integer> func = x -> x % 2 == 0 ? x * 2 : x / 2;
System.out.println(func.apply(5));
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
10%
10
8%
5
60%
2
23%
Exception какой-нибудь
Диалог с ревью🤪

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩‍💻

Какой метод возвращает случайное число от 0 до 1?
Anonymous Quiz
17%
System.random()
4%
Math.next()
17%
Random.nextDouble()
62%
Math.random()
Аннотация @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
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Аннотация @Any в Spring

Аннотация @Any относится к пакету org.hibernate.annotations (Hibernate, не Spring), но часто используется в Spring-приложениях, работающих с JPA/Hibernate. Она применяется для обозначения полиморфных ассоциаций, когда сущность может ссылаться на разные типы объектов.

@Any позволяет моделировать связь, где поле может содержать экземпляр любой сущности (из заданного набора), а не только строго определённого типа (как в @ManyToOne или @OneToOne).

Параметры и настройки

Аннотация @Any сама по себе не принимает параметров, но требует дополнительных аннотаций для корректной работы:

@AnyMetaDef (или @AnyMetaDefs для нескольких определений) – определяет метаданные для полиморфной связи:

name (обязательный)уникальное имя определения, которое используется в @Any.
metaType (по умолчанию String)тип идентификатора, хранящего информацию о классе (обычно String или Integer).
idType (обязательный)тип первичного ключа связанных сущностей (например, Long).
metaValuesмассив @MetaValue, где каждое значение связывает идентификатор класса с конкретной сущностью.

Пример:
@AnyMetaDef(
name = "animalMetaDef",
metaType = "string",
idType = "long",
metaValues = {
@MetaValue(value = "DOG", targetEntity = Dog.class),
@MetaValue(value = "CAT", targetEntity = Cat.class)
}
)


@JoinColumn указывает столбец в БД, хранящий ID связанной сущности.
@Column (опционально)указывает столбец, хранящий тип сущности (если метаданные используют отдельный столбец).

Пример использования
@Entity
public class Zoo {
@Id
private Long id;

@Any(metaDef = "animalMetaDef", metaColumn = @Column(name = "animal_type"))
@JoinColumn(name = "animal_id")
private Animal animal; // Может быть Dog или Cat
}


Жизненный цикл @Any

Загрузка (@PostLoad)
Hibernate определяет тип сущности по значению в metaColumn и загружает соответствующий объект.

Сохранение (@PrePersist/@PreUpdate)
перед сохранением Hibernate записывает:
ID сущности в animal_id.
Класс сущности (например, "DOG") в animal_type.


Удаление
каскадное удаление не поддерживается автоматически, нужно обрабатывать вручную.

Механизмы Spring и Spring Boot, связанные с @Any

Поскольку @Any – это аннотация Hibernate, её работа зависит от:
spring.jpa.hibernate.ddl-auto (в application.properties/application.yml) – если стоит update или create, Hibernate автоматически создаст таблицы с полями animal_id и animal_type.
spring.jpa.show-sql – полезно для отладки запросов, связанных с полиморфными ассоциациями.
EntityManager – Spring Boot автоматически настраивает его, и через него происходят все операции с @Any.


Ограничения и альтернативы
Нет встроенной поддержки в Spring Data JPA – репозитории не могут автоматически генерировать запросы для @Any.

Альтернативы:
@OneToMany + наследование (@Inheritance(strategy = InheritanceType.SINGLE_TABLE)) – если типы известны заранее.
@ElementCollection + Map<String, Object> – если полиморфизм нужен только для хранения данных.

#Java #Training #Hard #Spring #Hibernate #Any
Что выведет код?

import java.util.function.Predicate;

public class Task040425 {
public static void main(String[] args) {
Predicate<String> p1 = s -> s.length() > 4;
Predicate<String> p2 = s -> s.startsWith("J");

System.out.println(p1.and(p2).test("Java"));
}
}


#Tasks
Бедные, и ведь не отойти 😂

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩‍💻

Какой метод преобразует объект в строку в StringBuilder?
Anonymous Quiz
12%
getString()
8%
build()
73%
toString()
6%
convert()
Аннотация @BatchSize в Spring (Hibernate)

Аннотация @BatchSize принадлежит пакету org.hibernate.annotations и используется для оптимизации загрузки коллекций или прокси-объектов в Hibernate. Она позволяет загружать элементы пакетно (batch), уменьшая количество SQL-запросов (проблема N+1).

Применяется в двух случаях:
Для коллекций (@OneToMany, @ManyToMany) – загружает несколько связанных коллекций одним запросом.
Для лениво загружаемых сущностей (
@ManyToOne, @OneToOne) – загружает несколько прокси-объектов партиями.

Параметры и настройки
У аннотации есть один обязательный параметр - size: размер пакета (сколько элементов загружать за один SQL-запрос), обычно 10, 20, 50.

Примеры использования
Пакетная загрузка коллекций (N+1 Problem Fix)
@Entity
public class Author {
@Id
private Long id;

@OneToMany(mappedBy = "author")
@BatchSize(size = 10) // Загружает до 10 книг за один запрос
private List<Book> books;
}


Как работает:
Если загружается 100 авторов, без @BatchSize Hibernate выполнит 100+1 запрос (1 для авторов + 100 для книг каждого).
С
@BatchSize(size=10) Hibernate сделает 1 запрос для авторов + 10 запросов для книг (каждый запрос загружает книги для 10 авторов).

Пакетная загрузка ленивых сущностей
@Entity
public class Book {
@Id
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@BatchSize(size = 5) // Загружает авторов пачками по 5
private Author author;
}


Как работает:
При обращении к book.getAuthor(), Hibernate не загружает автора сразу, а ждёт, пока не потребуются несколько авторов.
Когда накопятся 5 ленивых прокси, Hibernate выполнит один запрос вида:


SELECT * FROM author WHERE id IN (1, 2, 3, 4, 5)


Жизненный цикл

Инициализация прокси/коллекции – Hibernate откладывает загрузку до первого обращения.
Пакетная загрузка – при достижении size или принудительной инициализации (например, Hibernate.initialize()).
Кэширование – загруженные объекты помещаются в кэш первого уровня (Session).


Настройки Hibernate в Spring Boot

@BatchSize работает на уровне Hibernate, но Spring Boot позволяет управлять его поведением через:
spring.jpa.properties.hibernate.default_batch_fetch_size (в
application.properties)

spring.jpa.properties.hibernate.default_batch_fetch_size=20
Устанавливает глобальный размер пакета для всех ленивых загрузок.


Если
@BatchSize указан на поле, он имеет приоритет.

Оптимизация запросов

JOIN FETCH (в JPQL) загружает данные одним запросом, но может привести к Cartesian Product.
@BatchSize даёт баланс между количеством запросов и объёмом данных.
@BatchSize можно комбинировать с @EntityGraph, но обычно @EntityGraph полностью отключает ленивую загрузку.

#Java #Training #Hard #Spring #Hibernate #BatchSize