ΠΠ°Π½ΠΈΡΠ΅ΡΡ ΠΈΠ½ΠΆΠ΅Π½Π΅ΡΠ°: ΠΠ°ΠΊ Π·Π°ΡΡΠ°Π²ΠΈΡΡ JVM Π»Π΅ΡΠ°ΡΡ, Π° Native Image - Π±ΡΡΡ ΠΊΠΎΠΌΠΏΠ°ΠΊΡΠ½ΡΠΌ.
Π’ΠΠ-10+1 "ΠΠΎΠ»ΠΎΡΡΡ ΠΏΡΠ°Π²ΠΈΠ» ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΉ Java 21+: ΠΊΠ°ΠΊ Π·Π°ΡΡΠ°Π²ΠΈΡΡ JIT ΠΏΠ΅ΡΡ, Π° GraalVM - Π»Π΅ΡΠ°ΡΡ"
ΠΡΠΎΡ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΉ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ ΠΏΡΠΈΠΌΠ΅ΡΡ ΠΊΠΎΠ΄Π° ΠΈ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΡΠΉ ΡΠ°Π·Π±ΠΎΡ 11 Π·ΠΎΠ»ΠΎΡΡΡ ΠΏΡΠ°Π²ΠΈΠ» ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π΄Π»Ρ Java 21+, Spring Boot 3 ΠΈ GraalVM Native Image.
ΠΠΎΡΠ΅ΠΌΡ Π²Π°ΡΠ° Java-ΡΠΈΡΡΠ΅ΠΌΠ° Π±ΡΠΊΡΡΠ΅Ρ ΡΠ°ΠΌ, Π³Π΄Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° Π»Π΅ΡΠ°ΡΡ? ΠΡ ΠΏΡΠΈΠ²ΡΠΊΠ»ΠΈ Π΄ΠΎΠ²Π΅ΡΡΡΡ ΠΌΠ°Π³ΠΈΠΈ JVM, Π½ΠΎ Π² ΠΌΠΈΡΠ΅ Java 21 ΠΈ Native Image ΠΏΡΠ°Π²ΠΈΠ»Π° ΠΈΠ³ΡΡ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ»ΠΈΡΡ. ΠΡ ΠΌΠΈΠΊΡΠΎ-ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΉ Π±Π°ΠΉΡ-ΠΊΠΎΠ΄Π° Π΄ΠΎ ΡΠ°Π΄ΠΈΠΊΠ°Π»ΡΠ½ΠΎΠΉ ΡΠΌΠ΅Π½Ρ ΠΏΠ°ΡΠ°Π΄ΠΈΠ³ΠΌΡ Ρ Scoped Values β ΡΠ°Π·Π±ΠΈΡΠ°Π΅ΠΌ 11 "Π·ΠΎΠ»ΠΎΡΡΡ ΠΏΡΠ°Π²ΠΈΠ»", ΠΊΠΎΡΠΎΡΡΠ΅ Π·Π°ΡΡΠ°Π²ΡΡ JIT ΠΏΠ΅ΡΡ, Π° Π²Π°Ρ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ β ΡΡΠ°ΡΡΠΎΠ²Π°ΡΡ Π·Π° ΠΌΠΈΠ»Π»ΠΈΡΠ΅ΠΊΡΠ½Π΄Ρ. ΠΠΈΠΊΠ°ΠΊΠΎΠΉ "Π²ΠΎΠ΄Ρ", ΡΠΎΠ»ΡΠΊΠΎ Ρ Π°ΡΠ΄ΠΊΠΎΡ, ΡΠ΅Π³ΠΈΡΡΡΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ° ΠΈ "Π³ΠΎΠ»ΠΎΡΠ°" ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡΠΎΠ² Π²Π½ΡΡΡΠΈ Π²Π°ΡΠ΅Π³ΠΎ ΠΊΠΎΠ΄Π°.
Π Π°Π±ΠΎΡΠ°Ρ Ρ ΠΊΠΎΠ΄ΠΎΠΌ, Ρ Π½Π΅ ΡΠ°Π· Π»ΠΎΠ²ΠΈΠ» Π°Π·Π°ΡΡ: Π° ΠΊΠ°ΠΊ ΡΡΠΎΡ ΠΌΠ΅ΡΠΎΠ΄ ΠΌΠΎΠΆΠ½ΠΎ ΡΡΠΊΠΎΡΠΈΡΡ Π΅ΡΡ? ΠΠ°ΠΊΡΡ Π³Π°ΠΉΠΊΡ ΠΏΠΎΠ΄ΠΊΡΡΡΠΈΡΡ, ΡΡΠΎΠ±Ρ JVM Π½Π΅ ΠΏΡΠΎΡΡΠΎ ΡΠ°Π±ΠΎΡΠ°Π»Π°, Π° Π±ΡΠΊΠ²Π°Π»ΡΠ½ΠΎ Π»Π΅ΡΠ΅Π»Π°? Π§ΡΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ Π² Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ΅, ΡΡΠΎΠ±Ρ Native Image ΡΡΠ°Π» Π΅ΡΡ ΠΊΠΎΠΌΠΏΠ°ΠΊΡΠ½Π΅Π΅, Π° Ρ ΠΎΠ»ΠΎΠ΄Π½ΡΠΉ ΡΡΠ°ΡΡ β Π΅ΡΡ Π±ΡΡΡΡΠ΅Π΅?
ΠΡΠΏΡΡΠ°Π² ΡΡΠΎΡ Π°Π·Π°ΡΡ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π½Π΅ ΡΠ°Π·, Ρ Ρ ΠΎΡΡ ΠΏΠΎΠ΄Π΅Π»ΠΈΡΡΡΡ ΠΈΠΌ Ρ Π²Π°ΠΌΠΈ. Π― ΡΠΎΠ±ΡΠ°Π» ΠΊΠ²ΠΈΠ½ΡΡΡΡΠ΅Π½ΡΠΈΡ ΡΠ²ΠΎΠ΅Π³ΠΎ ΠΎΠΏΡΡΠ° Π² ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΠΉ ΡΠ΅ΠΊ-Π»ΠΈΡΡ.
ΠΡΠΎ Π½Π΅ ΠΏΡΠΎΡΡΠΎ ΡΠΎΠ²Π΅ΡΡ ΠΏΠΎ ΡΡΠΈΠ»Ρ ΠΊΠΎΠ΄Π°. ΠΡΠΎ "10+1 ΠΠΎΠ»ΠΎΡΡΡ ΠΏΡΠ°Π²ΠΈΠ» ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Java 21+".
ΠΡΠΎ ΡΠ΅ ΡΡΡΠ°Π³ΠΈ, ΠΊΠΎΡΠΎΡΡΠ΅ Π·Π°ΡΡΠ°Π²Π»ΡΡΡ JIT-ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡ ΠΏΠ΅ΡΡ, Π° GraalVM β Π³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°ΡΡ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊΠΈ Ρ Ρ ΠΈΡΡΡΠ³ΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠΎΡΠ½ΠΎΡΡΡΡ.
ΠΡΠΈΠ³ΠΎΡΠΎΠ²ΡΡΠ΅ΡΡ! ΠΡ Π½Π°ΡΠΈΠ½Π°Π΅ΠΌ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ!
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β1. Records ΠΊΠ°ΠΊ DTO (Immutability & Heap)
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β2. fillInStackTrace(null) Π² Π±ΠΈΠ·Π½Π΅Ρ-ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡΡ
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β3. Final Π²Π΅Π·Π΄Π΅
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β4. Π‘ΠΌΠ΅ΡΡΡ Π Π΅ΡΠ»Π΅ΠΊΡΠΈΠΈ (AOT-friendly)
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β5. ΠΠΎΡΠΎΡΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ (Inlining Threshold)
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β6. ΠΡΠ΅Π°Π»Π»ΠΎΠΊΠ°ΡΠΈΡ ΠΊΠΎΠ»Π»Π΅ΠΊΡΠΈΠΉ
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β7. BigDecimal vs Long (ΠΠΈΡΠ²Π° Π·Π° ΠΏΡΠΈΠΌΠΈΡΠΈΠ²Ρ)
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β8. ΠΠ·Π±Π΅Π³Π°ΠΉΡΠ΅ ΠΏΡΠΎΠΊΡΠΈ Π² ΠΊΡΠΈΡΠΈΡΠ΅ΡΠΊΠΈΡ ΡΠ·Π»Π°Ρ
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β9. Generics: ΠΠ·Π±Π΅Π³Π°Π΅ΠΌ Π»ΠΈΡΠ½ΠΈΡ ΠΊΠ°ΡΡΠΎΠ²
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β10. Π‘ΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· Π²ΠΌΠ΅ΡΡΠΎ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ (MapStruct)
- ΠΡΠ°Π²ΠΈΠ»ΠΎ β11. Scoped Values Π²ΠΌΠ΅ΡΡΠΎ ThreadLocal
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: ΠΠ±ΡΡΠ½ΡΠ΅ POJO Ρ ΡΠ΅ΡΡΠ΅ΡΠ°ΠΌΠΈ β ΡΡΠΎ "ΡΡΡΠ½ΡΠΉ ΡΡΠΈΠΊ". ΠΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡ ΠΏΠΎΡΡΠΎΡΠ½Π½ΠΎ Π½Π°ΡΠ΅ΠΊΡ: Π²Π΄ΡΡΠ³ ΠΊΡΠΎ-ΡΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π² ΡΠ΅ΡΠ΅Π΄ΠΈΠ½Π΅ ΠΌΠ΅ΡΠΎΠ΄Π°? ΠΡΠΎ ΠΌΠ΅ΡΠ°Π΅Ρ Π³Π»ΡΠ±ΠΎΠΊΠΎΠΉ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΠΈ ΡΡΠ»ΠΎΠΆΠ½ΡΠ΅Ρ Π°Π½Π°Π»ΠΈΠ· Π³ΡΠ°ΡΠ° ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ².
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ record Π΄Π»Ρ Π²ΡΠ΅Ρ Π΄Π°Π½Π½ΡΡ , ΠΊΠΎΡΠΎΡΡΠ΅ ΠΏΡΠΎΡΡΠΎ "Π»Π΅ΡΡΡ" ΡΠΊΠ²ΠΎΠ·Ρ ΡΠΈΡΡΠ΅ΠΌΡ.
public record UserUpsertRequest (
@NotBlank(message = VALIDATE_USER_USERNAME_BLANK)
@Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_USERNAME_INCORRECT_SIZE)
@Pattern(regexp = LATIN_REGEX, message = VALIDATE_USER_USERNAME_INCORRECT_REGEX)
String username,
@NotBlank(message = VALIDATE_USER_PASSWORD_BLANK)
@Size(min = PASSWORD_SIZE_MIN, max = PASSWORD_SIZE_MAX, message = VALIDATE_USER_PASSWORD_INCORRECT_SIZE)
String password,
@NotBlank(message = VALIDATE_USER_FIRSTNAME_BLANK)
@Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_FIRSTNAME_INCORRECT_SIZE)
@Pattern(regexp = CYRILLIC_REGEX, message = VALIDATE_USER_FIRSTNAME_INCORRECT_REGEX)
String firstName,
@Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_SECONDNAME_INCORRECT_SIZE)
@Pattern(regexp = CYRILLIC_REGEX, message = VALIDATE_USER_SECONDNAME_INCORRECT_REGEX)
String secondName,
@NotBlank(message = VALIDATE_USER_LASTNAME_BLANK)
@Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_LASTNAME_INCORRECT_SIZE)
@Pattern(regexp = CYRILLIC_REGEX, message = VALIDATE_USER_LASTNAME_INCORRECT_REGEX)
String lastName,
@NotBlank(message = VALIDATE_USER_EMAIL_BLANK)
@Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_EMAIL_INCORRECT_SIZE)
@Email(regexp = EMAIL_REGEX, message = VALIDATE_USER_EMAIL_INCORRECT_REGEX)
String email
) {
}ΠΠΎΠ»ΠΎΡ JIT: "Π, record! ΠΠ°ΠΊΠΎΠ½Π΅Ρ-ΡΠΎ Ρ Π²ΠΈΠΆΡ final ΠΏΠΎΠ»Ρ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ. Π’Π΅ΠΏΠ΅ΡΡ Ρ ΡΠΎΡΠ½ΠΎ Π·Π½Π°Ρ, ΡΡΠΎ Π΄Π°Π½Π½ΡΠ΅ Π½Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡΡ ΠΏΠΎΡΠ»Π΅ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ. Π― ΠΌΠΎΠ³Ρ Π°Π³ΡΠ΅ΡΡΠΈΠ²Π½Π΅Π΅ ΠΏΡΠΈΠΌΠ΅Π½ΡΡΡ Scalar Replacement (ΡΠ°Π·Π»ΠΎΠΆΠΈΡΡ ΠΎΠ±ΡΠ΅ΠΊΡ Π½Π° ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅) ΠΈ Π·Π°ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΡΡ Π΄ΠΎΡΡΡΠΏ ΠΊ Π½ΠΈΠΌ ΠΏΡΡΠΌΠΎ Π² ΡΠ΅Π³ΠΈΡΡΡΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ°".
Π¨ΡΠΏΠΎΡ AOT: "ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΡΡΡΡΠΊΡΡΡΠ° record ΠΈΠ·Π²Π΅ΡΡΠ½Π° ΠΌΠ½Π΅ Π΅ΡΡ Π½Π° ΡΡΠ°ΠΏΠ΅ ΡΠ±ΠΎΡΠΊΠΈ, Ρ ΠΌΠΎΠ³Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ ΡΡΠΈΡ Π΄Π°Π½Π½ΡΡ Π² Π±ΠΈΠ½Π°ΡΠ½ΡΠΉ ΠΊΠΎΠ΄ Π³ΠΎΡΠ°Π·Π΄ΠΎ Π°Π³ΡΠ΅ΡΡΠΈΠ²Π½Π΅Π΅, ΡΠ΅ΠΌ Π΄Π»Ρ ΠΎΠ±ΡΡΠ½ΡΡ ΠΊΠ»Π°ΡΡΠΎΠ² Ρ ΠΈΡ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΎΠΉ ΠΏΡΠΈΡΠΎΠ΄ΠΎΠΉ".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: ΠΡ ΡΠ°ΡΡΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ Exception Π΄Π»Ρ Π»ΠΎΠ³ΠΈΠΊΠΈ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, UserNotFound). ΠΠΎ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡ β ΡΡΠΎ Π½Π΅ ΠΏΡΠΎΡΡΠΎ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ°, ΡΡΠΎ Π΄ΠΎΡΠΎΠ³ΠΎΠ΅ "ΠΏΡΡΠ΅ΡΠ΅ΡΡΠ²ΠΈΠ΅" ΠΏΠΎ Π²ΡΠ΅ΠΌΡ ΡΡΠ΅ΠΊΡ Π²ΡΠ·ΠΎΠ²ΠΎΠ² Π΄Π»Ρ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΌΠ°ΡΡΠΈΠ²Π° StackStraceElement[]. ΠΠ° ΡΡΠΎ ΡΡ ΠΎΠ΄ΠΈΡ Π΄ΠΎ 90% Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ "ΠΆΠΈΠ·Π½ΠΈ" ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡ.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ»Ρ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·ΡΠ΅ΠΌΡΡ Π±ΠΈΠ·Π½Π΅Ρ-ΠΎΡΠΈΠ±ΠΎΠΊ, Π³Π΄Π΅ Π²Π°ΠΌ Π½Π΅ Π½ΡΠΆΠ΅Π½ Π»ΠΎΠ³ ΡΠΎ Π²ΡΠ΅ΠΌΠΈ Π²Π½ΡΡΡΠ΅Π½Π½ΠΎΡΡΡΠΌΠΈ ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊΠ°, ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΠ΅ ΡΠ±ΠΎΡ ΡΡΠ΅ΠΊΡΡΠ΅ΠΉΡΠ°.
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message, null, false, false); // Π΅ΡΡ Π±ΡΡΡΡΠ΅Π΅ ΡΠ΅ΡΠ΅Π· ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡ
}
@Override
public synchronized Throwable fillInStackTrace() {
// ΠΡ Π½Π΅ ΡΠΎΠ±ΠΈΡΠ°Π΅ΠΌ ΡΡΠ°ΡΡΠΈΡΠΎΠ²ΠΊΡ ΡΡΠ΅ΠΊΠ°, ΡΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠΊΠΎΠ½ΠΎΠΌΠΈΡΡ ΡΠ΅ΡΡΡΡΡ CPU
return this;
}
}ΠΠΎΠ»ΠΎΡ JIT: "Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ! ΠΠΎΠ³Π΄Π° Π²Ρ ΡΠΎΠ·Π΄Π°ΡΡΠ΅ ΠΎΠ±ΡΡΠ½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅, Ρ Π²ΡΠ½ΡΠΆΠ΄Π΅Π½ Π±ΡΠΎΡΠΈΡΡ Π²ΡΡ ΠΈ ΠΏΠΎΠ±Π°ΠΉΡΠΎΠ²ΠΎ Π²ΠΎΡΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°ΡΡ ΡΠ΅ΠΏΠΎΡΠΊΡ Π²ΡΠ·ΠΎΠ²ΠΎΠ². ΠΡΠΎΡ ΠΊΠ°ΠΊ ΡΡΠ°Π²ΠΈΡΡ ΡΠΈΠ»ΡΠΌ Π½Π° ΠΏΠ°ΡΠ·Ρ, ΡΡΠΎΠ±Ρ ΠΏΠ΅ΡΠ΅ΡΡΠΈΡΠ°ΡΡ Π²ΡΠ΅ ΠΊΠ°Π΄ΡΡ. Π‘ ΡΡΠΈΠΌ ΠΏΡΠ°Π²ΠΈΠ»ΠΎΠΌ Ρ ΠΏΡΠΎΡΡΠΎ ΡΠΎΠ·Π΄Π°Ρ ΠΎΠ±ΡΠ΅ΠΊΡ ΠΈ Π±Π΅Π³Ρ Π΄Π°Π»ΡΡΠ΅, ΡΠΎΡ ΡΠ°Π½ΡΡ ΡΠ΅ΠΌΠΏ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ".
Π¨ΡΠΏΠΎΡ AOT: "Π Native Image ΠΊΠ°ΠΆΠ΄ΡΠΉ ΡΡΠ΅ΠΊΡΡΠ΅ΠΉΡ β ΡΡΠΎ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ ΠΌΠ΅ΡΠ°-ΠΊΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΌΠ΅ΡΡ Π²ΠΎΡΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°ΡΡ Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅. Π£Π±ΠΈΡΠ°Ρ
fillInStackTrace, Π²Ρ Π½Π΅ ΡΠΎΠ»ΡΠΊΠΎ ΡΡΠΊΠΎΡΡΠ΅ΡΠ΅ Π»ΠΎΠ³ΠΈΠΊΡ, Π½ΠΎ ΠΈ Π΄Π΅Π»Π°Π΅ΡΠ΅ ΠΌΠΎΠΉ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ ΠΊΠΎΠΌΠΏΠ°ΠΊΡΠ½Π΅Π΅, ΠΈΠ·Π±Π°Π²Π»ΡΡ ΠΌΠ΅Π½Ρ ΠΎΡ Π»ΠΈΡΠ½ΠΈΡ ΡΠ°Π±Π»ΠΈΡ ΠΌΠ΅ΡΠ°Π΄Π°Π½Π½ΡΡ ".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: ΠΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ½Π½ΠΎΡΡΡ. ΠΡΠ»ΠΈ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ Π½Π΅ ΠΏΠΎΠΌΠ΅ΡΠ΅Π½Π° ΠΊΠ°ΠΊ final, ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΡΠΈΡΡΠ²Π°ΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ Π΅Ρ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² Π»ΡΠ±ΠΎΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ. ΠΡΠΎ ΡΠ°Π·Π΄ΡΠ²Π°Π΅Ρ Π³ΡΠ°Ρ ΡΠΎΡΡΠΎΡΠ½ΠΈΠΉ, ΠΊΠΎΡΠΎΡΡΠΉ Π½ΡΠΆΠ½ΠΎ Π°Π½Π°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΡΠΈ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ΅Π»Π°ΠΉΡΠ΅ final Π»ΠΎΠΊΠ°Π»ΡΠ½ΡΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅, ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² ΠΈ ΠΏΠΎΠ»Ρ ΠΊΠ»Π°ΡΡΠΎΠ². ΠΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ ΠΊΠΎΠ΄ β ΡΡΠΎ ΠΏΡΠ΅ΠΆΠ΄Π΅ Π²ΡΠ΅Π³ΠΎ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·ΡΠ΅ΠΌΡΠΉ ΠΊΠΎΠ΄. Π§Π΅ΠΌ ΠΌΠ΅Π½ΡΡΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ
ΠΌΠΎΠ³ΡΡ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ ΡΠ²ΠΎΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅, ΡΠ΅ΠΌ Π°Π³ΡΠ΅ΡΡΠΈΠ²Π½Π΅Π΅ ΡΠ°Π±ΠΎΡΠ°ΡΡ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΎΡΡ.
public Resource exportDataToCsvResource() {
final List<Statistics> data = statisticsRepository.findAll();
final StringBuilder builder = new StringBuilder(data.size() * 64);
builder.append(FIRST_ROW_OF_CSV);
for (final Statistics stat : data) {
builder.append(stat.getId()).append(DELIMITER_CSV)
.append(stat.getType()).append(DELIMITER_CSV)
.append(stat.getUserId()).append(DELIMITER_CSV)
.append(stat.getCheckIn()).append(DELIMITER_CSV)
.append(stat.getCheckOut()).append(DELIMITER_CSV)
.append(stat.getCreatedAt()).append('\n');
}
final byte[] bytes = builder.toString().getBytes(StandardCharsets.UTF_8);
return new ByteArrayResource(bytes);
}ΠΠΎΠ»ΠΎΡ JIT: "ΠΠΈΠΆΡ
finalβ Π΄Π΅Π»Π°Ρ Constant Folding. ΠΡΠ»ΠΈ Ρ ΡΠ²Π΅ΡΠ΅Π½, ΡΡΠΎ ΡΡΡΠ»ΠΊΠ° Π½Π° ΠΎΠ±ΡΠ΅ΠΊΡ ΠΈΠ»ΠΈ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π½Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡΡ, Ρ ΠΌΠΎΠ³Ρ Π²ΡΠΊΠΈΠ½ΡΡΡ Π»ΠΈΡΠ½ΠΈΠ΅ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ ΠΈΠ· ΠΌΠ°ΡΠΈΠ½Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° ΠΈ Π΄Π°ΠΆΠ΅ Π·Π°ΡΠ°Π½Π΅Π΅ Π²ΡΡΠΈΡΠ»ΠΈΡΡ ΡΠ΅Π·ΡΠ»ΡΡΠ°Ρ Π½Π΅ΠΊΠΎΡΠΎΡΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ. ΠΠ»Ρ ΠΌΠ΅Π½Ρ final β ΡΡΠΎ Π½Π΅ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΠ΅, Π° Π·Π΅Π»ΡΠ½ΡΠΉ ΡΠ²Π΅Ρ: "ΠΠ΄Π΅ΡΡ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎ, ΠΆΠΌΠΈ Π½Π° Π³Π°Π·!".
Π¨ΡΠΏΠΎΡ AOT: "ΠΠ»Ρ ΠΌΠ΅Π½Ρ
finalβ ΡΡΠΎ Π±Π°Π·Π° Π΄Π»Ρ Dead Code Elimination. ΠΡΠ»ΠΈ Ρ Π²ΠΈΠΆΡ ΠΊΠΎΠ½ΡΡΠ°Π½ΡΠ½ΠΎΠ΅ ΡΡΠ»ΠΎΠ²ΠΈΠ΅, Ρ ΠΌΠΎΠ³Ρ ΠΏΡΠΎΡΡΠΎ "ΠΎΡΡΠ΅Π·Π°ΡΡ" ΡΠ΅Π»ΡΠ΅ Π²Π΅ΡΠΊΠΈ ΠΊΠΎΠ΄Π°, ΠΊΠΎΡΠΎΡΡΠ΅ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ ΠΈΡΠΏΠΎΠ»Π½ΡΡΡΡ. ΠΡΠΎ Π΄Π΅Π»Π°Π΅Ρ Π±ΠΈΠ½Π°ΡΠ½ΡΠΉ ΡΠ°ΠΉΠ» ΠΌΠ΅Π½ΡΡΠ΅, Π° Π»ΠΎΠ³ΠΈΠΊΡ - ΠΏΡΡΠΌΠΎΠ»ΠΈΠ½Π΅ΠΉΠ½Π΅Π΅".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: Π Π΅ΡΠ»Π΅ΠΊΡΠΈΡ β ΡΡΠΎ "ΡΡΡΠ½Π°Ρ Π΄ΡΡΠ°" Π΄Π»Ρ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ. JIT Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ Π·Π°ΡΠ°Π½Π΅Π΅ Π·Π°Π³Π»ΡΠ½ΡΡΡ Π²Π½ΡΡΡΡ Π²ΡΠ·ΠΎΠ²Π° ΡΠ΅ΡΠ΅Π· Method.invoke(), Π° Native Image ΠΈ Π²ΠΎΠ²ΡΠ΅ ΡΡΠ΅Π±ΡΠ΅Ρ ΠΎΠΏΠΈΡΡΠ²Π°ΡΡ ΠΊΠ°ΠΆΠ΄ΡΠΉ ΡΠ°ΠΊΠΎΠΉ "ΡΠΈΡ
" Π² JSON-ΠΊΠΎΠ½ΡΠΈΠ³Π°Ρ
. ΠΡΠ»ΠΈ Π²Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΠ΅ ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΡ Π² ΠΊΡΠΈΡΠΈΡΠ΅ΡΠΊΠΎΠΌ ΡΠ·Π»Π΅, Π²Ρ Π΄ΠΎΠ±ΡΠΎΠ²ΠΎΠ»ΡΠ½ΠΎ ΠΎΡΠΊΠ°Π·ΡΠ²Π°Π΅ΡΠ΅ΡΡ ΠΎΡ 30-50% ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»ΡΠ½ΠΎΠΉ ΡΠΊΠΎΡΠΎΡΡΠΈ.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ MapStruct, JOOQ ΠΈ Π΄ΡΡΠ³ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ, ΡΠ°Π±ΠΎΡΠ°ΡΡΠΈΠ΅ ΡΠ΅ΡΠ΅Π· ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅ΡΠ°ΡΠΈΡ (APT). ΠΠ½ΠΈ ΡΠΎΠ·Π΄Π°ΡΡ ΡΠΈΡΡΡΠΉ Java-ΠΊΠΎΠ΄ Π½Π° ΡΡΠ°ΠΏΠ΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ, ΠΊΠΎΡΠΎΡΡΠΉ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ°ΠΊ, Π±ΡΠ΄ΡΠΎ Π²Ρ Π½Π°ΠΏΠΈΡΠ°Π»ΠΈ Π΅Π³ΠΎ ΡΡΠΊΠ°ΠΌΠΈ - Ρ ΠΏΡΡΠΌΡΠΌΠΈ Π²ΡΠ·ΠΎΠ²Π°ΠΌΠΈ Π³Π΅ΡΡΠ΅ΡΠΎΠ² ΠΈ ΡΠ΅ΡΡΠ΅ΡΠΎΠ².
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING,
unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface UserMapper {
User requestToUser(UserUpsertRequest request);
UserResponse userToResponse(User user);
default UserListResponse userListToUserListResponse(List<User> users) {
return new UserListResponse(users
.stream()
.map(this::userToResponse)
.toList());
}
@Mapping(target = "id", ignore = true)
@Mapping(target = "username", ignore = true)
@Mapping(target = "password", ignore = true)
@Mapping(target = "roles", ignore = true)
@Mapping(target = "createAt", ignore = true)
@Mapping(target = "updateAt", ignore = true)
void updateUser(UserUpsertRequest request, @MappingTarget User user);
}ΠΠΎΠ»ΠΎΡ JIT: "Π Π΅ΡΠ»Π΅ΠΊΡΠΈΡ Π΄Π»Ρ ΠΌΠ΅Π½Ρ β ΡΡΠΎ ΠΊΠ°ΠΊ ΡΡΠΌΠ°Π½ Π½Π° ΡΡΠ°ΡΡΠ΅. Π― Π½Π΅ Π²ΠΈΠΆΡ, ΡΡΠΎ Π²ΠΏΠ΅ΡΠ΅Π΄ΠΈ ΠΈ ΡΠ½ΠΈΠΆΠ°Ρ ΡΠΊΠΎΡΠΎΡΡΡ Π΄ΠΎ ΠΌΠΈΠ½ΠΈΠΌΡΠΌΠ°, ΠΎΡΠΊΠ»ΡΡΠ°Ρ Π²ΡΠ΅ ΡΠ²ΠΎΠΈ ΡΡΠΏΠ΅ΡΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡΠΈ. Π ΠΊΠΎΠ΄ ΠΎΡ MapStruct β ΡΡΠΎ ΠΏΡΡΠΌΠΎΠΉ Π°Π²ΡΠΎΠ±Π°Π½. Π― Π²ΠΈΠΆΡ
entity.getName()->dto.setName()ΠΈ ΠΏΡΠΎΡΡΠΎ "ΠΏΡΠΎΡΠΈΠ²Π°Ρ" ΡΡΠΎΡ Π²ΡΠ·ΠΎΠ² Π½Π°ΡΠΊΠ²ΠΎΠ·Ρ ΡΠ΅ΡΠ΅Π· Inlining".
Π¨ΡΠΏΠΎΡ AOT: "Π Π΅ΡΠ»Π΅ΠΊΡΠΈΡ β ΠΌΠΎΠΉ Π½ΠΎΡΠ½ΠΎΠΉ ΠΊΠΎΡΠΌΠ°Ρ. Π§ΡΠΎΠ±Ρ ΠΎΠ½Π° Π·Π°ΡΠ°Π±ΠΎΡΠ°Π»Π° Π² Native Image, ΠΌΠ½Π΅ Π½ΡΠΆΠ½ΠΎ ΡΠ°ΡΠΈΡΡ Π·Π° ΡΠΎΠ±ΠΎΠΉ ΠΊΡΡΡ ΠΌΠ΅ΡΠ°Π΄Π°Π½Π½ΡΡ , ΡΡΠΎ ΡΠ°Π·Π΄ΡΠ²Π°Π΅Ρ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ. ΠΠΎΠ΄ΠΎΠ³Π΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΌΠ½Π΅ Π²ΡΠΊΠΈΠ½ΡΡΡ Π²ΡΡ Π»ΠΈΡΠ½Π΅Π΅ Π΅ΡΡ ΠΏΡΠΈ ΡΠ±ΠΎΡΠΊΠ΅. ΠΠ΅Π½ΡΡΠ΅ ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΠΈ β ΠΌΠ΅Π½ΡΡΠ΅ reflect-config.json ΠΈ Π±ΡΡΡΡΠ΅Π΅ ΡΡΠ°ΡΡ".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: ΠΠΈΠ³Π°Π½ΡΡΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Π½Π° 500 ΡΡΡΠΎΠΊ, ΠΊΠΎΡΠΎΡΡΠ΅ Π΄Π΅Π»Π°ΡΡ Π²ΡΡ: Π²Π°Π»ΠΈΠ΄ΠΈΡΡΡΡ, ΡΡΠΈΡΠ°ΡΡ, Π»ΠΎΠ³ΠΈΡΡΡΡ ΠΈ ΡΠΎΡ ΡΠ°Π½ΡΡΡ. JIT Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ ΠΈΡ "ΠΏΡΠΎΠ³Π»ΠΎΡΠΈΡΡ" (Π²ΡΡΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΠ½ Π² Π΄ΡΡΠ³ΠΎΠΉ), ΠΏΠΎΡΠΎΠΌΡ ΡΡΠΎ ΠΎΠ½ΠΈ ΠΏΡΠ΅Π²ΡΡΠ°ΡΡ Π»ΠΈΠΌΠΈΡΡ ΠΏΠΎ ΡΠ°Π·ΠΌΠ΅ΡΡ Π±Π°ΠΉΡ-ΠΊΠΎΠ΄Π°. Π ΠΈΡΠΎΠ³Π΅ ΠΊΠ°ΠΆΠ΄ΡΠΉ Π²ΡΠ·ΠΎΠ² ΡΡΠΎΠ³ΠΎ ΠΌΠ΅ΡΠΎΠ΄Π° β ΡΡΠΎ ΡΠ΅ΡΡΠ½ΡΠΉ ΠΏΠ΅ΡΠ΅Ρ ΠΎΠ΄ ΠΏΠΎ Π°Π΄ΡΠ΅ΡΡ Π² ΠΏΠ°ΠΌΡΡΠΈ, ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΡΠ΅ΠΉΠΌΠ° Π² ΡΡΠ΅ΠΊΠ΅ ΠΈ ΠΊΡΡΠ° Π»ΠΈΡΠ½ΠΈΡ ΡΠ°ΠΊΡΠΎΠ² ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ°.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠΎΠ±ΠΈΡΠ΅ Π»ΠΎΠ³ΠΈΠΊΡ Π½Π° ΠΌΠ΅Π»ΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ. ΠΠ΄Π΅Π°Π»ΡΠ½ΡΠΉ ΡΠ°Π·ΠΌΠ΅Ρ Π΄Π»Ρ ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΠ½Π³Π° β Π΄ΠΎ 35 Π±Π°ΠΉΡ Π±Π°ΠΉΡ-ΠΊΠΎΠ΄Π°. ΠΡΠ°ΡΠΈΠ²ΡΠΉ ΠΊΠΎΠ΄ ΠΏΠΎ Clean Code Π²Π½Π΅Π·Π°ΠΏΠ½ΠΎ ΠΎΠΊΠ°Π·ΡΠ²Π°Π΅ΡΡΡ ΡΠ°ΠΌΡΠΌ Π±ΡΡΡΡΡΠΌ Π΄Π»Ρ ΠΌΠ°ΡΠΈΠ½Ρ.
@Before("@annotation(AuthoriseUserCreateByAnonymous)")
public void validateRoleTypeForAnonymousUserCreate(JoinPoint joinPoint) {
HttpServletRequest request = getRequest();
loggingOperation(joinPoint, request);
Authentication auth = getAuth();
if (!auth.getName().equals(ANONYMOUS_USER)) {
AppUserPrincipal principal =
((AppUserPrincipal) auth.getPrincipal());
if (isAdmin(principal)) {
return;
}
throw new ForbiddenException(TEMPLATE_OPERATION_FORBIDDEN);
}
if (isRoleTypeUser(joinPoint)) {
return;
}
throw new ForbiddenException(TEMPLATE_OPERATION_FORBIDDEN);
}
private HttpServletRequest getRequest() {
RequestAttributes requestAttributes =
RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
throw new ForbiddenException(TEMPLATE_OPERATION_FORBIDDEN);
}
return ((ServletRequestAttributes) requestAttributes).getRequest();
}
private void loggingOperation(JoinPoint joinPoint,
HttpServletRequest request) {
Map<String, String> pathVariables =
(Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
Authentication auth =
SecurityContextHolder.getContext().getAuthentication();
log.info(CALL_OPERATION,
auth.getName(),
joinPoint.getSignature().getName(),
pathVariables.toString(),
Arrays.toString(joinPoint.getArgs()));
}
private Authentication getAuth() {
return SecurityContextHolder.getContext().getAuthentication();
}
private AppUserPrincipal getUserDetails() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) {
throw new UserNotAuthenticatedException(TEMPLATE_OPERATION_UNAUTHORIZED);
}
return (AppUserPrincipal) auth.getPrincipal();
}ΠΠΎΠ»ΠΎΡ JIT: "Π£ ΠΌΠ΅Π½Ρ Π΅ΡΡΡ ΠΆΡΡΡΠΊΠΈΠΉ Π»ΠΈΠΌΠΈΡ MaxInlineSize. ΠΡΠ»ΠΈ ΠΌΠ΅ΡΠΎΠ΄ ΠΊΡΠΎΡ ΠΎΡΠ½ΡΠΉ, Ρ ΠΏΡΠΎΡΡΠΎ ΠΊΠΎΠΏΠΈΡΡΡ Π΅Π³ΠΎ ΡΠ΅Π»ΠΎ Π² ΠΌΠ΅ΡΡΠΎ Π²ΡΠ·ΠΎΠ²Π°. ΠΡΠ°Π½ΠΈΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΌΠ΅ΡΠΎΠ΄Π°ΠΌΠΈ ΠΈΡΡΠ΅Π·Π°ΡΡ, ΠΊΠΎΠ΄ ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡΡ ΠΌΠΎΠ½ΠΎΠ»ΠΈΡΠ½ΡΠΌ ΠΈ Π»Π΅ΡΠΈΡ ΡΠΎ ΡΠΊΠΎΡΠΎΡΡΡΡ ΡΠ²Π΅ΡΠ°. ΠΠ³ΡΠΎΠΌΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Ρ Π²ΡΠ½ΡΠΆΠ΄Π΅Π½ Π²ΡΠ·ΡΠ²Π°ΡΡ "ΠΏΠΎ ΡΡΠ°ΡΠΈΠ½ΠΊΠ΅" - Ρ ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΠ΅ΠΌ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΡΡΠ΅ΠΊΠ° ΠΈ ΠΏΡΡΠΆΠΊΠ°ΠΌΠΈ ΠΏΠΎ Π°Π΄ΡΠ΅ΡΠ°ΠΌΠΈ. ΠΡΠ΄ΡΡΠ΅ ΠΏΡΠΎΡΠ΅, ΠΈ Ρ ΡΠ΄Π΅Π»Π°Ρ Π²Π°Ρ ΠΊΠΎΠ΄ ΠΏΠΎ-Π½Π°ΡΡΠΎΡΡΠ΅ΠΌΡ Π±ΡΡΡΡΡΠΌ!"
Π¨ΡΠΏΠΎΡ AOT: "Π Native Image Ρ ΠΏΡΠΎΠ²ΠΎΠΆΡ Π³Π»ΡΠ±ΠΎΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· Π΄ΠΎΡΡΠΈΠΆΠΈΠΌΠΎΡΡΠΈ ΠΊΠΎΠ΄Π°. ΠΠ΅Π»ΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡΡ ΠΌΠ½Π΅ ΡΠΎΡΠ½Π΅Π΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΡ, ΠΊΠ°ΠΊΠΈΠ΅ ΡΠ°ΡΡΠΈ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π±ΡΠ΄ΡΡ Π²ΡΠ·Π²Π°Π½Ρ, ΠΈ ΠΏΠΎΠ»Π½ΠΎΡΡΡΡ Π²ΡΡΠ΅Π·Π°ΡΡ ΠΈΡ ΠΏΡΠΈ ΡΠ±ΠΎΡΠΊΠ΅. Π§Π΅ΠΌ ΡΠΈΡΠ΅ ΡΡΡΡΠΊΡΡΡΠ° Π²Π°ΡΠΈΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ², ΡΠ΅ΠΌ ΡΡΡΠΎΠΉΠ½Π΅Π΅ ΠΈ Π±ΡΡΡΡΠ΅Π΅ ΠΈΡΠΎΠ³ΠΎΠ²ΡΠΉ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: Π‘ΠΎΠ·Π΄Π°Π²Π°Ρ new ArrayList<>(), new HashMap<>() ΠΈ Π΄ΡΡΠ³ΠΈΠ΅ ΡΡΡΡΠΊΡΡΡΡ Π΄Π°Π½Π½ΡΡ
Π±Π΅Π· ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ², Π²Ρ ΠΏΠΎΠ΄ΠΏΠΈΡΡΠ²Π°Π΅ΡΠ΅ JVM Π½Π° ΡΠ΅ΡΠΈΡ "ΠΏΠ΅ΡΠ΅Π΅Π·Π΄ΠΎΠ²". ΠΠ°ΠΊ ΡΠΎΠ»ΡΠΊΠΎ ΡΠΏΠΈΡΠΎΠΊ Π½Π°ΠΏΠΎΠ»Π½ΡΠ΅ΡΡΡ, ΠΎΠ½ ΡΠΎΠ·Π΄Π°ΡΡ ΠΌΠ°ΡΡΠΈΠ² ΠΏΠΎΠ±ΠΎΠ»ΡΡΠ΅ ΠΈ ΠΊΠΎΠΏΠΈΡΡΠ΅Ρ ΡΡΠ΄Π° ΡΡΠ°ΡΡΠ΅ Π΄Π°Π½Π½ΡΠ΅. ΠΡΠΎ Π»ΠΈΡΠ½ΠΈΠ΅ Π°Π»Π»ΠΎΠΊΠ°ΡΠΈΠΈ, ΡΡΠ°Π³ΠΌΠ΅Π½ΡΠ°ΡΠΈΡ ΠΏΠ°ΠΌΡΡΠΈ ΠΈ ΡΠ°Π±ΠΎΡΠ° Π΄Π»Ρ GC.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ°Π΄Π°Π²Π°ΠΉΡΠ΅ Initial Capacity. Π Java 19+ Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΠΏΠΎΡΠ²ΠΈΠ»ΠΈΡΡ Π΅ΡΡ Π±ΠΎΠ»Π΅Π΅ ΡΠ΄ΠΎΠ±Π½ΡΠ΅ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ, ΠΊΠΎΡΠΎΡΡΠ΅ ΡΠ°ΠΌΠΈ ΡΡΠΈΡΡΠ²Π°ΡΡ ΠΊΠΎΡΡΡΠΈΡΠΈΠ΅Π½Ρ Π·Π°Π³ΡΡΠ·ΠΊΠΈ (Load Factor).
import java.util.LinkedHashMap;
private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
// ΠΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎΠ΅ Π²ΡΠ΄Π΅Π»Π΅Π½ΠΈΠ΅ 16 buckets
Map<String, Object> errorProperties = LinkedHashMap.newLinkedHashMap(16);
errorProperties.putAll(getErrorAttributes(request,
ErrorAttributeOptions.defaults()));
int status =
(int) errorProperties.getOrDefault("status", 500);
return ServerResponse.status(status)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(errorProperties)
.doOnNext(resp -> log.error("ΠΡΠΈΠ±ΠΊΠ° Π·Π°ΠΏΡΠΎΡΠ°: [{}]: {}",
status,
errorProperties));
}ΠΠΎΠ»ΠΎΡ JIT: "ΠΠ°ΠΆΠ΄ΡΠΉ ΡΠ°Π·, ΠΊΠΎΠ³Π΄Π° ΠΌΠ°ΡΡΠΈΠ² Π²Π½ΡΡΡΠΈ ΠΊΠΎΠ»Π»Π΅ΠΊΡΠΈΠΈ ΡΠ°ΡΡΠΈΡΡΠ΅ΡΡΡ, Ρ ΡΠ»ΡΡΡ ΠΏΠ»Π°Ρ Garbage Collectorβa. ΠΠ°ΡΠ°Π½Π΅Π΅ Π·Π°Π΄Π°Π½Π½ΡΠΉ ΡΠ°Π·ΠΌΠ΅Ρ β ΡΡΠΎ ΠΊΠ°ΠΊ Π·Π°Π±ΡΠΎΠ½ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ ΡΡΠΎΠ»ΠΈΠΊ Π² ΡΠ΅ΡΡΠΎΡΠ°Π½Π΅: Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ ΡΡΠ΅ΡΡ ΠΈ Π»ΠΈΡΠ½ΠΈΡ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠΉ. Π― ΠΏΡΠΎΡΡΠΎ Π²ΡΠ΄Π΅Π»ΡΡ ΠΎΠ΄ΠΈΠ½ ΠΊΡΡΠΎΠΊ ΠΏΠ°ΠΌΡΡΠΈ ΠΈ ΡΠΏΠΎΠΊΠΎΠΉΠ½ΠΎ ΡΠ°Π±ΠΎΡΠ°Ρ Ρ Π½ΠΈΠΌ, Π½Π΅ ΠΎΡΠ²Π»Π΅ΠΊΠ°ΡΡΡ Π½Π° ΠΏΠ΅ΡΠ΅ΠΊΠ»Π°Π΄ΡΠ²Π°Π½ΠΈΠ΅ Π±Π°ΠΉΡΠΎΠ²".
Π¨ΡΠΏΠΎΡ AOT: "Π Native Image ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡΡΡ Π΅ΡΡ Π±ΠΎΠ»Π΅Π΅ ΡΡΡΠΎΠ³ΠΎΠ΅. ΠΡΠ΅Π°Π»Π»ΠΎΠΊΠ°ΡΠΈΡ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΌΠ½Π΅ Π»ΡΡΡΠ΅ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·Π°ΡΡ ΠΏΠΈΠΊΠΎΠ²ΠΎΠ΅ ΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΠ΅ RAM Π²Π°ΡΠΈΠΌ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ. Π§Π΅ΠΌ ΠΌΠ΅Π½ΡΡΠ΅ Ρ Π²Π°Ρ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΡ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠΉ ΠΌΠ°ΡΡΠΈΠ²ΠΎΠ², ΡΠ΅ΠΌ ΡΡΠ°Π±ΠΈΠ»ΡΠ½Π΅Π΅ ΠΈ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·ΡΠ΅ΠΌΠ΅Π΅ Π²Π΅Π΄ΡΡ ΡΠ΅Π±Ρ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ ΠΏΠΎΠ΄ Π½Π°Π³ΡΡΠ·ΠΊΠΎΠΉ".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: BigDecimal β ΡΡΠΎ ΡΡΠΆΡΠ»ΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ, Π²Π½ΡΡΡΠΈ ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ ΡΠΊΡΡΡ ΠΌΠ°ΡΡΠΈΠ² int[]. ΠΡΠ±Π°Ρ Π°ΡΠΈΡΠΌΠ΅ΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ Ρ Π½ΠΈΠΌ β ΡΡΠΎ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π² ΠΏΠ°ΠΌΡΡΠΈ. Π Π±ΠΈΠ»Π»ΠΈΠ½Π³Π΅ ΠΈΠ»ΠΈ Π²ΡΡΠΎΠΊΠΎΠ½Π°Π³ΡΡΠΆΠ΅Π½Π½ΡΡ
ΡΠ°ΡΡΡΡΠ°Ρ
ΡΡΠΎ Π³Π΅Π½Π΅ΡΠΈΡΡΠ΅Ρ ΡΠΎΠ½Π½Ρ ΠΌΡΡΠΎΡΠ° Π² ΠΏΠ°ΠΌΡΡΠΈ, Π·Π°ΡΡΠ°Π²Π»ΡΡ GC ΡΠ°Π±ΠΎΡΠ°ΡΡ Π½Π° ΠΈΠ·Π½ΠΎΡ.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: Π₯ΡΠ°Π½ΠΈΡΠ΅ Π΄Π΅Π½Π΅ΠΆΠ½ΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ Π² ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΡΡ
Π΅Π΄ΠΈΠ½ΠΈΡΠ°Ρ
(ΠΊΠΎΠΏΠ΅ΠΉΠΊΠΈ, ΡΠ΅Π½ΡΡ) Π² ΡΠΈΠΏΠ΅ long. ΠΠ΅ΡΠ΅Ρ
ΠΎΠ΄ΠΈΡΠ΅ Π½Π° BigDecimal ΡΠΎΠ»ΡΠΊΠΎ Π² ΡΠ°ΠΌΡΠΉ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ β ΠΏΡΠΈ Π²ΡΠ²ΠΎΠ΄Π΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ.
public record WalletResponse(
long amount, // long - ΡΡΠΎ Π±ΡΡΡΡΠΎ
String currency
) {
// Π’ΠΎΠ»ΡΠΊΠΎ Π΄Π»Ρ ΠΊΡΠ°ΡΠΎΡΡ ΠΏΡΠΈ Π²ΡΠ²ΠΎΠ΄Π΅
public BigDecimal getDisplayAmount() {
return BigDecimal.valueOf(amount, 2);
}
}ΠΠΎΠ»ΠΎΡ JIT: "
longβ ΡΡΠΎ ΠΏΡΠΎΡΡΠΎ 64 Π±ΠΈΡΠ° Π² ΠΌΠΎΡΠΌ ΡΠ΅Π³ΠΈΡΡΡΠ΅. Π― Ρ ΡΠ°Π½Ρ Π΅Π³ΠΎ ΠΏΡΡΠΌΠΎ Π² ΡΠ΅Π³ΠΈΡΡΡΠ°Ρ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ°. Π‘Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄Π²ΡΡlongΠ·Π°Π½ΠΈΠΌΠ°Π΅Ρ Π΄ΠΎΠ»ΠΈ Π½Π°Π½ΠΎΡΠ΅ΠΊΡΠ½Π΄Ρ. Π‘BigDecimalΡ Π²ΡΠ½ΡΠΆΠ΄Π΅Π½ ΠΏΡΡΠ³Π°ΡΡ Π² ΠΊΡΡΡ (Heap) Π·Π° ΠΊΠ°ΠΆΠ΄ΡΠΌ ΡΠΈΡΠ»ΠΎΠΌ ΠΈ Π΅Π³ΠΎ ΠΌΠ°ΡΡΡΠ°Π±ΠΎΠΌ. ΠΡΠ±ΠΈΡΠ°ΠΉΡΠ΅ long, Π΅ΡΠ»ΠΈ Π½Π΅ Ρ ΠΎΡΠΈΡΠ΅, ΡΡΠΎΠ±Ρ Ρ Π±ΡΠΊΡΠΎΠ²Π°Π» Π½Π° ΡΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠ½ΠΎΠΉ Π°ΡΠΈΡΠΌΠ΅ΡΠΈΠΊΠ΅".
Π¨ΡΠΏΠΎΡ AOT: "Π Π±ΠΈΠ½Π°ΡΠ½ΠΎΠΌ ΠΊΠΎΠ΄Π΅ Native Image ΡΠ°Π±ΠΎΡΠ° Ρ
longΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅ΡΡΡ Π² ΠΎΠ΄Π½Ρ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΡ Π°ΡΡΠ΅ΠΌΠ±Π»Π΅ΡΠ°.BigDecimalΠΆΠ΅ ΡΡΠ½Π΅Ρ Π·Π° ΡΠΎΠ±ΠΎΠΉ Π΄Π΅ΡΠ΅Π²ΠΎ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ ΠΈ ΡΠ»ΠΎΠΆΠ½ΡΡ Π»ΠΎΠ³ΠΈΠΊΡ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΏΠ°ΠΌΡΡΡΡ. Π§Π΅ΠΌ Π±ΠΎΠ»ΡΡΠ΅ ΠΏΡΠΈΠΌΠΈΡΠΈΠ²ΠΎΠ², ΡΠ΅ΠΌ ΠΌΠ΅Π½ΡΡΠ΅ ΠΌΠΎΠΉ ΠΈΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌΡΠΉ ΡΠ°ΠΉΠ» ΠΈ ΡΠ΅ΠΌ Π±ΡΡΡΡΠ΅Π΅ ΠΎΠ½ "ΠΏΡΠΎΠ³ΡΠ΅Π²Π°Π΅ΡΡΡ"".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: @Transactional ΠΈ @Async, @Cacheable - ΡΡΠΎ ΡΠ΄ΠΎΠ±Π½ΠΎ, Π½ΠΎ Π·Π° ΠΊΡΠ»ΠΈΡΠ°ΠΌΠΈ ΠΎΠ½ΠΈ ΡΠΎΠ·Π΄Π°ΡΡ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΠΎΠ±Π΅ΡΡΠΊΠΈ (Proxy) Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅. ΠΠ°ΠΆΠ΄ΡΠΉ Π²ΡΠ·ΠΎΠ² ΠΏΡΠΎΠΊΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΠΌΠ΅ΡΠΎΠ΄Π° - ΡΡΠΎ Π»ΠΈΡΠ½ΠΈΠΉ "ΠΏΡΡΠΆΠΎΠΊ" ΠΏΠΎ ΠΎΠ±ΡΠ΅ΠΊΡΠ°ΠΌ-ΠΏΠ΅ΡΠ΅Ρ
Π²Π°ΡΡΠΈΠΊΠ°ΠΌ, ΡΠ°Π·Π΄ΡΡΡΠΉ ΡΡΠ΅ΠΊ Π²ΡΠ·ΠΎΠ²ΠΎΠ² ΠΈ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ Π³Π»ΡΠ±ΠΎΠΊΠΎΠ³ΠΎ ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΠ½Π³Π°. Π Π²ΡΡΠΎΠΊΠΎΠ½Π°Π³ΡΡΠΆΠ΅Π½Π½ΡΡ
ΡΠΈΠΊΠ»Π°Ρ
ΡΡΠΎ ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡΡ Π½Π°ΡΡΠΎΡΡΠΈΠΌ "ΡΡΠ΅ΠΊ-ΠΊΠΈΠ»Π»Π΅ΡΠΎΠΌ".
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ΅ΡΠΆΠΈΡΠ΅ Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΡ "ΡΠΈΡΡΠΎΠΉ". ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ Π°Π½Π½ΠΎΡΠ°ΡΠΈΠΈ ΡΠΎΠ»ΡΠΊΠΎ Π½Π° Π²Π΅ΡΡ
Π½Π΅ΠΌ ΡΡΠΎΠ²Π½Π΅ (Entry Points), Π° Π²Π½ΡΡΡΠΈ ΡΠ΅ΡΠ²ΠΈΡΠΎΠ² Π²ΡΠ·ΡΠ²Π°ΠΉΡΠ΅ ΠΎΠ±ΡΡΠ½ΡΠ΅ private/package-private ΠΌΠ΅ΡΠΎΠ΄Ρ. ΠΡΠ»ΠΈ Π²Π°ΠΌ Π½ΡΠΆΠ½ΠΎ Π²ΡΠ·Π²Π°ΡΡ @Transactional ΠΌΠ΅ΡΠΎΠ΄ ΠΈΠ· ΡΠΎΠ³ΠΎ ΠΆΠ΅ ΠΊΠ»Π°ΡΡΠ° - Π²Ρ ΡΠΆΠ΅ Π·Π½Π°Π΅ΡΠ΅, ΡΡΠΎ ΠΏΡΠΎΠΊΡΠΈ Π½Π΅ ΡΡΠ°Π±ΠΎΡΠ°Π΅Ρ (self-invocation), ΠΈ ΡΡΠΎ ΠΎΡΠ»ΠΈΡΠ½ΡΠΉ ΠΏΠΎΠ²ΠΎΠ΄ Π·Π°Π΄ΡΠΌΠ°ΡΡΡΡ ΠΎ Π΄Π΅ΠΊΠΎΠΌΠΏΠΎΠ·ΠΈΡΠΈΠΈ.
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class UserService {
@Value("${app.kafka.kafkaStatisticsService.kafkaUserCreatedStatus}")
private String kafkaUserCreatedStatus;
private final PasswordEncoder passwordEncoder;
private final UserRepository userRepository;
private final UserMapper userMapper;
private final KafkaTemplate<String, Object> kafkaTemplate;
public List<User> findAll(UserFilter userFilter) {
return userRepository.fetchAll(
UserSpecification.withFilter(userFilter),
PageRequest.of(
userFilter.pageNumber(),
userFilter.pageSize()
)
).getContent();
}
public User findById(UUID id) {
return userRepository.findById(id)
.orElseThrow(() ->
new EntityNotFoundException(MessageFormat.format(TEMPLATE_USER_NOT_FOUND_EXCEPTION, id)));
}
public User findByUsername(String username) {
return userRepository.findByUsername(username)
.orElseThrow(() ->
new UsernameNotFoundException("Username not found!"));
}
@AuthoriseUserCreateByAnonymous
@Transactional
public UUID save(User user, RoleType roleType) {
// ΠΎΠ±ΡΡΠ½ΡΠΉ Π²ΡΠ·ΠΎΠ² ΠΌΠ΅ΡΠΎΠ΄Π°
userRepository.findUserIdByUsernameAndEmail(
user.getUsername(),
user.getEmail()
).ifPresent(id -> {
throw new UserAlreadyExistsException(
MessageFormat.format(TEMPLATE_USER_ALREADY_EXISTS_EXCEPTION,
user.getUsername(),
user.getEmail()));
});
user.setRoles(new ArrayList<>(List.of(roleType)));
user.setPassword(passwordEncoder.encode(user.getPassword()));
UUID userId = userRepository.saveAndFlush(user).getId();
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronization() {
@Override
public void afterCommit() {
kafkaTemplate.send(kafkaUserCreatedStatus,
new UserRegistrationEvent(userId)
);
}
}
);
return userId;
}
@AuthoriseUserUpdateAndDelete
@Transactional
public UUID update(UUID userId, UserUpsertRequest request, RoleType roleType) {
// ΠΎΠ±ΡΡΠ½ΡΠΉ Π²ΡΠ·ΠΎΠ² ΠΌΠ΅ΡΠΎΠ΄Π°
User existedUser = findById(userId);
userMapper.updateUser(request, existedUser);
if (request.password() != null && !request.password().isBlank()) {
existedUser.setPassword(passwordEncoder.encode(request.password()));
}
if (roleType != null) {
existedUser.getRoles().clear();
existedUser.getRoles().add(roleType);
}
return userRepository.saveAndFlush(existedUser).getId();
}
@AuthoriseUserUpdateAndDelete
@Transactional
public void delete(UUID id) {
findById(id);
userRepository.deleteById(id);
}
}ΠΠΎΠ»ΠΎΡ JIT: "ΠΡΠΎΠΊΡΠΈ Π΄Π»Ρ ΠΌΠ΅Π½Ρ β ΡΡΠΎ Π»Π°Π±ΠΈΡΠΈΠ½Ρ. Π― Π²ΠΈΠΆΡ ΡΠ΅ΠΏΠΎΡΠΊΡ ΡΠ³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°Π½Π½ΡΡ ΠΊΠ»Π°ΡΡΠΎΠ²-ΠΎΠ±Π΅ΡΡΠΎΠΊ, ΡΠ΅ΡΠ΅Π· ΠΊΠΎΡΠΎΡΡΠ΅ Π½ΡΠΆΠ½ΠΎ ΠΏΡΠΎΠ΄ΡΠ°ΡΡΡΡ ΠΊ ΡΠ΅Π°Π»ΡΠ½ΠΎΠΌΡ ΠΊΠΎΠ΄Ρ. Π§Π΅ΠΌ ΠΌΠ΅Π½ΡΡΠ΅ ΠΌΠ°Π³ΠΈΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΠΌΠ½ΠΎΠΉ ΠΈ Π²Π°ΡΠΈΠΌ ΠΊΠΎΠ΄ΠΎΠΌ, ΡΠ΅ΠΌ Π±ΡΡΡΡΠ΅Π΅ Ρ ΠΏΠΎΡΡΡΠΎΡ ΠΏΡΡΠΌΠΎΠΉ Π³ΡΠ°Ρ Π²ΡΠ·ΠΎΠ²ΠΎΠ² ΠΈ ΠΏΡΠΈΠΌΠ΅Π½Ρ inlining".
Π¨ΡΠΏΠΎΡ AOT: "ΠΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΠΏΡΠΎΠΊΡΠΈ β ΠΌΠΎΠΉ Π²ΡΠ°Π³ Π½ΠΎΠΌΠ΅Ρ ΠΎΠ΄ΠΈΠ½. Π§ΡΠΎΠ±Ρ ΠΎΠ½ΠΈ ΡΠ°Π±ΠΎΡΠ°Π»ΠΈ Π² Native Image, ΠΌΠ½Π΅ ΠΏΡΠΈΡ ΠΎΠ΄ΠΈΡΡΡ Π³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°ΡΡ ΠΈΡ Π·Π°ΡΠ°Π½Π΅Π΅ ΠΈΠ»ΠΈ ΡΠ°ΡΠΈΡΡ ΡΡΠΆΡΠ»ΡΠΉ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌ ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΠΈ. Π£Π±ΠΈΡΠ°Ρ Π»ΠΈΡΠ½ΠΈΠ΅ ΠΏΡΠΎΠΊΡΠΈ, Π²Ρ ΡΠΌΠ΅Π½ΡΡΠ°Π΅ΡΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠ³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°Π½Π½ΡΡ ΠΊΠ»Π°ΡΡΠΎΠ² Π² Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊΠ΅ ΠΈ ΡΡΠΊΠΎΡΡΠ΅ΡΠ΅ Π·Π°ΠΏΡΡΠΊ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: Π₯ΠΎΡΡ Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅ ΡΠΈΠΏΡ ΡΡΠΈΡΠ°ΡΡΡΡ (Type Erasure), ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ Object ΠΈΠ»ΠΈ Raw Types Π·Π°ΡΡΠ°Π²Π»ΡΠ΅Ρ Π²Π°Ρ (ΠΈ JVM) ΠΏΠΎΡΡΠΎΡΠ½Π½ΠΎ Π²ΡΡΠ°Π²Π»ΡΡΡ Π² Π±Π°ΠΉΡ-ΠΊΠΎΠ΄ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΡ checkcast. ΠΡΠΎ Π½Π΅ ΡΠΎΠ»ΡΠΊΠΎ Π½Π΅Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎ, Π½ΠΎ ΠΈ Π·Π°ΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡ ΡΡΠ°ΡΠΈΡΡ Π»ΠΈΡΠ½ΠΈΠ΅ ΡΠ°ΠΊΡΡ Π½Π° ΠΏΡΠΎΠ²Π΅ΡΠΊΡ ΠΈΠ΅ΡΠ°ΡΡ
ΠΈΠΈ ΠΊΠ»Π°ΡΡΠΎΠ² ΠΏΡΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΠΎΠ±ΡΠ°ΡΠ΅Π½ΠΈΠΈ ΠΊ ΠΎΠ±ΡΠ΅ΠΊΡΡ.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΡΡΡΠΎΠ³ΠΎ ΡΠΈΠΏΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ Π΄ΠΆΠ΅Π½Π΅ΡΠΈΠΊΠΈ Π²Π΅Π·Π΄Π΅, Π³Π΄Π΅ Π²Π°ΠΆΠ½Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ. ΠΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡΡ Π³Π°ΡΠ°Π½ΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠΈΠΏΡ Π½Π° ΡΡΠ°ΠΏΠ΅ ΡΠ±ΠΎΡΠΊΠΈ, Π° JIT-ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΎΡΡ - ΡΡΡΠΎΠΈΡΡ ΠΌΠ°ΡΠΈΠ½Π½ΡΠΉ ΠΊΠΎΠ΄ Π±Π΅Π· Π»ΠΈΡΠ½ΠΈΡ "ΠΊΠΎΠ½ΡΡΠΎΠ»ΡΠ½ΠΎ-ΠΏΡΠΎΠΏΡΡΠΊΠ½ΡΡ ΠΏΡΠ½ΠΊΡΠΎΠ²".
@RequiredArgsConstructor
@Component
public class ValidatorHandler {
private final Validator validator;
// ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ <T> Π³Π°ΡΠ°Π½ΡΠΈΡΡΠ΅Ρ, ΡΡΠΎ Π½Π° Π²ΡΡ
ΠΎΠ΄Π΅ Π±ΡΠ΄Π΅Ρ ΡΠΎΡ ΠΆΠ΅ ΡΠΈΠΏ, ΡΡΠΎ ΠΈ Π½Π° Π²Ρ
ΠΎΠ΄Π΅
// ΠΠΈΠΊΠ°ΠΊΠΈΡ
ΡΡΡΠ½ΡΡ
(Cast) Π² Π²ΡΠ·ΡΠ²Π°ΡΡΠ΅ΠΌ ΠΊΠΎΠ΄Π΅!
public <T> Mono<T> validate(T body) {
return Mono.fromCallable(() -> {
var violations = validator.validate(body);
if (violations.isEmpty()) {
return body;
}
throw new ValidationException(buildErrorMessage(violations));
})
.subscribeOn(Schedulers.boundedElastic());
}
private String buildErrorMessage(Set<? extends ConstraintViolation<?>> violations) {
return violations
.stream()
.map(v ->
v.getPropertyPath() + ": " +
v.getMessage())
.collect(Collectors.joining("; "));
}
}ΠΠΎΠ»ΠΎΡ JIT: "ΠΠ°ΠΆΠ΄ΡΠΉ ΡΠ°Π·, ΠΊΠΎΠ³Π΄Π° Ρ Π²ΠΈΠΆΡ
checkcast, Ρ Π²ΡΠ½ΡΠΆΠ΄Π΅Π½ ΠΏΡΠΈΡΠΎΡΠΌΠΎΠ·ΠΈΡΡ ΠΈ ΠΏΡΠΎΠ²Π΅ΡΠΈΡΡ: Π° ΡΠΎΡΠ½ΠΎ Π»ΠΈ ΡΡΠΎΡ ΠΎΠ±ΡΠ΅ΠΊΡ Π² ΠΏΠ°ΠΌΡΡΠΈ ΡΠΎΠ²ΠΏΠ°Π΄Π°Π΅Ρ Ρ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΡΠΌ ΡΠΈΠΏΠΎΠΌ? Π‘ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΡΠΌΠΈ Π΄ΠΆΠ΅Π½Π΅ΡΠΈΠΊΠ°ΠΌΠΈ Ρ Π΄ΠΎΠ²Π΅ΡΡΡ Π²Π°ΡΠ΅ΠΌΡ ΠΊΠΎΠ΄Ρ Π½Π° 100%. ΠΠ»Ρ ΠΌΠ΅Π½Ρ ΡΡΠΎ ΡΠΊΠΎΡΠΎΡΡΠ½Π°Ρ ΡΡΠ°ΡΡΠ° Π±Π΅Π· ΡΠ²Π΅ΡΠΎΡΠΎΡΠΎΠ² ΠΈ Π»ΠΈΡΠ½ΠΈΡ ΠΏΡΠΎΠ²Π΅ΡΠΎΠΊ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠΎΠ²".
Π¨ΡΠΏΠΎΡ AOT: "Π Native Image Ρ ΠΏΡΠΎΠ²ΠΎΠΆΡ Static Analysis Π²ΡΠ΅ΠΉ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ. Π‘ΡΡΠΎΠ³Π°Ρ ΡΠΈΠΏΠΈΠ·Π°ΡΠΈΡ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ ΠΌΠ½Π΅ ΡΠΎΡΠ½Π΅Π΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΡ Π³ΡΠ°Π½ΠΈΡΡ ΡΠΈΠΏΠΎΠ² ΠΈ ΠΈΡΠΊΠ»ΡΡΠΈΡΡ Π»ΠΈΡΠ½ΠΈΠ΅ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ ΠΈΠ· Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊΠ°. Π§Π΅ΠΌ ΠΌΠ΅Π½ΡΡΠ΅ "Π½Π΅ΠΈΠ·Π²Π΅ΡΡΠ½ΡΡ "
Object, ΡΠ΅ΠΌ ΠΌΠ΅Π½ΡΡΠ΅ ΠΏΡΠΎΠ²Π΅ΡΠΎΠΊ ΡΠΈΠΏΠΎΠ² Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅ ΠΈ Π²ΡΡΠ΅ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ".
ΠΡΠ°Π²ΠΈΠ»ΠΎ β10. Π‘ΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· Π²ΠΌΠ΅ΡΡΠΎ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΎΠ³ΠΎ (MapStruct)
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: ΠΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Π²ΡΠΎΠ΄Π΅ ModelMapper ΠΈΠ»ΠΈ Π·Π»ΠΎΡΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΠ΅ ObjectMapper.convertValue() - ΡΡΠΎ "Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΠΉ Π½Π°Π»ΠΎΠ³" Π½Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ. ΠΠ½ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ ΠΈΠ½ΡΡΠΎΡΠΏΠ΅ΠΊΡΠΈΡ Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅, Π±ΡΠΊΠ²Π°Π»ΡΠ½ΠΎ "ΠΎΡΡΠΏΡΠ²Π°Ρ" ΠΊΠ°ΠΆΠ΄ΡΠΉ ΠΎΠ±ΡΠ΅ΠΊΡ Π² ΠΏΠΎΠΈΡΠΊΠ°Ρ
ΠΏΠΎΠ΄Ρ
ΠΎΠ΄ΡΡΠΈΡ
ΠΏΠΎΠ»Π΅ΠΉ ΡΠ΅ΡΠ΅Π· getField() ΠΈ setAccessible(true). ΠΠ»Ρ JIT ΡΡΠΎ Π½Π΅ΠΏΡΠΎΠ·ΡΠ°ΡΠ½ΡΠΉ ΠΊΠΎΠ΄, Π° Π΄Π»Ρ Native Image - ΠΊΠΎΠ½ΡΠΈΠ³-Π°Π΄ Π½Π° ΡΡΡΡΡΠΈ ΡΡΡΠΎΠΊ.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΠ΅ΡΠ΅Π½ΠΎΡΠΈΡΠ΅ Π²ΡΡ ΡΠ»ΠΎΠΆΠ½ΠΎΡΡΡ Π½Π° ΡΡΠ°ΠΏ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ. ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅ΡΠ°ΡΠΈΡ. MapStruct Π³Π΅Π½Π΅ΡΠΈΡΡΠ΅Ρ ΠΎΠ±ΡΡΠ½ΡΠΉ Java-ΠΊΠΎΠ΄ target.set(source.get()) Π½Π° ΡΡΠ°ΠΏΠ΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ. ΠΡ ΡΠΆΠ΅ Π²ΠΈΠ΄Π΅Π»ΠΈ Π΅Π³ΠΎ ΠΌΠΎΡΡ Π² ΠΡΠ°Π²ΠΈΠ»Π΅ β4, Π½ΠΎ Π·Π΄Π΅ΡΡ ΠΏΠΎΠ΄ΡΠ΅ΡΠΊΠ½ΡΠΌ: Π½ΡΠ»Π΅Π²ΠΎΠΉ ΠΎΠ²Π΅ΡΡ Π΅Π΄ Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅ ΠΈ ΠΏΠΎΠ»Π½Π°Ρ ΠΏΡΠΎΠ·ΡΠ°ΡΠ½ΠΎΡΡΡ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΎΡΠΎΠ².
@RequiredArgsConstructor
@RequestMapping("/api/v1/user")
@RestController
public class UserController {
private static final String pathToUserResource = "/api/v1/user/{id}";
private final UserMapper userMapper;
private final UserService userService;
@GetMapping
public ResponseEntity<UserListResponse> findAll(@Valid UserFilter userFilter) {
// Π§ΠΈΡΡΡΠΉ ΠΌΠ°ΠΏΠΏΠΈΠ½Π³: Π½ΠΈ ΠΎΠ΄Π½ΠΎΠΉ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΠΈ Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅!
return ResponseEntity.ok(
userMapper.userListToUserListResponse(
userService.findAll(userFilter)
)
);
}
@GetMapping("/{id}")
public ResponseEntity<UserResponse> findById(@PathVariable UUID id) {
return ResponseEntity.ok(
userMapper.userToResponse(userService.findById(id))
);
}
@PostMapping
public ResponseEntity<Void> create(@RequestBody @Valid UserUpsertRequest request,
@RequestParam RoleType roleType) {
return ResponseEntity.created(getUri(
userService.save(
userMapper.requestToUser(request),
roleType
)
)).build();
}
@PutMapping("/{id}")
public ResponseEntity<Void> update(@PathVariable("id") UUID userId,
@RequestBody @Valid UserUpsertRequest request,
@RequestParam RoleType roleType) {
return ResponseEntity.ok()
.location(getUri(
userService.update(userId,
request,
roleType)
))
.build();
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable("id") UUID userId) {
userService.delete(userId);
return ResponseEntity.noContent().build();
}
private URI getUri(UUID id) {
return UriComponentsBuilder.fromPath(pathToUserResource)
.buildAndExpand(id)
.toUri();
}
}ΠΠΎΠ»ΠΎΡ JIT: "ΠΠ»Ρ ΠΌΠ΅Π½Ρ ΠΊΠΎΠ΄ ΠΎΡ MapStruct β ΡΡΠΎ ΠΏΠΎΠ΄Π°ΡΠΎΠΊ. ΠΡΠΎ ΠΏΡΡΠΌΠΎΠΉ, ΠΏΠΎΠ½ΡΡΠ½ΡΠΉ ΠΈ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·ΡΠ΅ΠΌΡΠΉ ΠΏΠΎΡΠΎΠΊ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΠΉ. Π― ΠΈΠ½Π»Π°ΠΉΠ½Ρ ΡΠ°ΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ, ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Ρ ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ Π² ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ Π±Π΅ΡΠΏΠ»Π°ΡΠ½ΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ. ΠΠΈΠΊΠ°ΠΊΠΈΡ ΠΏΠΎΠΈΡΠΊΠΎΠ² ΠΏΠΎ ΠΈΠΌΠ΅Π½Π°ΠΌ ΠΏΠΎΠ»Π΅ΠΉ Π² HashMap ΠΌΠ΅ΡΠ°Π΄Π°Π½Π½ΡΡ - ΡΠΎΠ»ΡΠΊΠΎ ΡΠ°Π±ΠΎΡΠ° Ρ ΡΠ΅Π³ΠΈΡΡΡΠ°ΠΌΠΈ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ°".
Π¨ΡΠΏΠΎΡ AOT: "Π‘ΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· β ΠΌΠΎΠΉ Π»ΡΡΡΠΈΠΉ Π΄ΡΡΠ³. ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ MapStruct Π³Π΅Π½Π΅ΡΠΈΡΡΠ΅Ρ ΠΎΠ±ΡΡΠ½ΡΠ΅ Π²ΡΠ·ΠΎΠ²Ρ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ², Ρ Π²ΠΈΠΆΡ Π²ΡΠ΅ ΡΠ²ΡΠ·ΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΠΊΠ»Π°ΡΡΠ°ΠΌΠΈ Π΅ΡΡ ΠΏΡΠΈ ΡΠ±ΠΎΡΠΊΠ΅ Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊΠ°. ΠΠ½Π΅ Π½Π΅ Π½ΡΠΆΠ½ΠΎ Π³Π°Π΄Π°ΡΡ, ΠΊΠ°ΠΊΠΈΠ΅ ΠΏΠΎΠ»Ρ Π²Ρ Π·Π°Ρ ΠΎΡΠΈΡΠ΅ "ΠΏΠΎΡΡΠΎΠ³Π°ΡΡ" ΡΠ΅ΡΠ΅Π· ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΡ, ΠΏΠΎΡΡΠΎΠΌΡ Ρ ΠΌΠΎΠ³Ρ ΡΠΌΠ΅Π»ΠΎ Π²ΡΡΠ΅Π·Π°ΡΡ Π²ΡΡ Π»ΠΈΡΠ½Π΅Π΅ ΠΈΠ· ΠΈΡΠΎΠ³ΠΎΠ²ΠΎΠ³ΠΎ ΡΠ°ΠΉΠ»Π°".
Π ΡΡΠΌ Π±ΠΎΠ»Ρ: ΠΡ Π΄Π΅ΡΡΡΠΈΠ»Π΅ΡΠΈΡΠΌΠΈ Ρ
ΡΠ°Π½ΠΈΠ»ΠΈ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΈΠ»ΠΈ ΡΡΠ°Π½Π·Π°ΠΊΡΠΈΠΈ Π² ThreadLocal. ΠΡΠΎ ΡΠ°Π±ΠΎΡΠ°Π»ΠΎ, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΡΠΎΠΊΠΎΠ² Π±ΡΠ»ΠΎ 200-500. ΠΠΎ Π² Java 21 Π²Ρ Π²ΠΊΠ»ΡΡΠ°Π΅ΡΠ΅ spring.threads.virtual.enabled: true ΠΈ Π·Π°ΠΏΡΡΠΊΠ°Π΅ΡΠ΅ 100_000 Π²ΠΈΡΡΡΠ°Π»ΡΠ½ΡΡ
ΠΏΠΎΡΠΎΠΊΠΎΠ². ΠΡΠ»ΠΈ ΠΊΠ°ΠΆΠ΄ΡΠΉ ΠΈΠ· Π½ΠΈΡ
"ΠΏΡΠΈΡΠΎΡΡΡΡΡ" ΠΊ ΡΡΠΆΡΠ»ΠΎΠΌΡ ΠΎΠ±ΡΠ΅ΠΊΡΡ Π² ThreadLocal, Π²Π°Ρ Heap Π»ΠΎΠΏΠ½Π΅Ρ Π±ΡΡΡΡΠ΅Π΅, ΡΠ΅ΠΌ ΡΡΠ°Π±ΠΎΡΠ°Π΅Ρ ΠΏΠ΅ΡΠ²ΡΠΉ GC. Π ΡΠΎΠΌΡ ΠΆΠ΅, ThreadLocal - ΡΡΠΎ ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΠ°Ρ ΡΡΡΡΠΊΡΡΡΠ°, ΡΡΠΎ ΡΠ°ΠΌΠΎ ΠΏΠΎ ΡΠ΅Π±Π΅ ΡΡΠ»ΠΎΠΆΠ½ΡΠ΅Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ.
ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅: ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ Scoped Values (JEP 446 / 464). ΠΠ½ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡΡ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡ Π½Π΅ΠΈΠ·ΠΌΠ΅Π½ΡΠ΅ΠΌΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ Π²Π½ΠΈΠ· ΠΏΠΎ Π΄Π΅ΡΠ΅Π²Ρ Π²ΡΠ·ΠΎΠ²ΠΎΠ². ΠΠ°ΠΊ ΡΠΎΠ»ΡΠΊΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π²ΡΡ
ΠΎΠ΄ΠΈΡ ΠΈΠ· Π±Π»ΠΎΠΊΠ° - Π΄Π°Π½Π½ΡΠ΅ ΡΡΠ°Π½ΠΎΠ²ΡΡΡΡ Π½Π΅Π΄ΠΎΡΡΡΠΏΠ½Ρ, Π° ΠΏΠ°ΠΌΡΡΡ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ Π³ΠΎΡΠΎΠ²Π° ΠΊ ΠΎΡΠΈΡΡΠΊΠ΅. ΠΠΈΠΊΠ°ΠΊΠΈΡ
ΡΡΠ΅ΡΠ΅ΠΊ ΠΈΠ·-Π·Π° Π·Π°Π±ΡΡΠΎΠ³ΠΎ .remove().
private final static ScopedValue<UserContext> CURRENT_USER = ScopedValue.newInstance();
public void handleRequest(UserContext context) {
// ΠΡΠΈΠ²ΡΠ·ΡΠ²Π°Π΅ΠΌ Π΄Π°Π½Π½ΡΠ΅ ΠΊ ΠΎΠ±Π»Π°ΡΡΠΈ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡΠΈ. (Scope)
ScopedValue.where(CURRENT_USER, context).run(() -> {
// ΠΠ½ΡΡΡΠΈ ΡΡΠΎΠ³ΠΎ Π±Π»ΠΎΠΊΠ° ΠΈ Π²ΡΠ΅Ρ
Π²Π»ΠΎΠΆΠ΅Π½Π½ΡΡ
ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ²
// CURRENT_USER.get() Π²Π΅ΡΠ½ΡΡ Π½Π°Ρ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡ.
// ΠΠΈΠΊΠ°ΠΊΠΈΡ
ΡΡΠ΅ΡΠ΅ΠΊ, Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ ΠΏΡΠΈΠ²ΡΠ·ΠΊΠΈ ΠΊ ΠΆΠΈΠ·Π½ΠΈ ΠΏΠΎΡΠΎΠΊΠ°!
processOrder();
});
}ΠΠΎΠ»ΠΎΡ JIT: "
ThreadLocalΠ΄Π»Ρ ΠΌΠ΅Π½Ρ - ΡΡΠΎ ΡΡΠΆΡΠ»ΡΠΉ ΡΡΠΊΠ·Π°ΠΊ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΡΠΎΠΊ Π½Π΅ ΡΠ½ΠΈΠΌΠ°Π΅Ρ Π΄ΠΎ ΡΠ°ΠΌΠΎΠΉ ΡΠΌΠ΅ΡΡΠΈ. Π― Π½Π΅ ΠΌΠΎΠ³Ρ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·Π°ΡΡ, ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ Π΅Π³ΠΎ ΡΠ½ΠΈΠΌΠ΅Ρ.Scoped Valueβ ΡΡΠΎ Π»ΡΠ³ΠΊΠ°Ρ ΡΡΡΠ°ΡΠ΅ΡΠ½Π°Ρ ΠΏΠ°Π»ΠΎΡΠΊΠ°: ΠΏΠΎΠ΄Π΅ΡΠΆΠ°Π», ΠΏΠ΅ΡΠ΅Π΄Π°Π», ΠΈ ΠΎΠ½Π° ΠΈΡΡΠ΅Π·Π»Π°. Π ΠΌΠΈΡΠ΅ ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π° Π²ΠΈΡΡΡΠ°Π»ΡΠ½ΡΡ ΠΏΠΎΡΠΎΠΊΠΎΠ² ΡΡΠΎ Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΡΠΉ ΡΠΏΠΎΡΠΎΠ± Π½Π΅ ΡΡΠΎΠ½ΡΡΡ Π² Π±Π΅ΡΠΊΠΎΠ½Π΅ΡΠ½ΡΡ ΠΌΠ°ΠΏΠ°Ρ Π²Π½ΡΡΡΠΈ ΠΏΠΎΡΠΎΠΊΠΎΠ²".
Π¨ΡΠΏΠΎΡ AOT: "ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΎΠ±Π»Π°ΡΡΡ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡΠΈ Scoped Value ΠΆΡΡΡΠΊΠΎ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π° Π±Π»ΠΎΠΊΠΎΠΌ ΠΊΠΎΠ΄Π°, Ρ ΠΌΠΎΠ³Ρ Π³ΠΎΡΠ°Π·Π΄ΠΎ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½Π΅Π΅ Π°Π½Π°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ Π²ΡΠ΅ΠΌΡ ΠΆΠΈΠ·Π½ΠΈ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ². ΠΡΠΎ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ ΠΌΠ½Π΅ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡΠΈ ΠΈ ΡΠΌΠ΅Π½ΡΡΠΈΡΡ Π½Π°ΠΊΠ»Π°Π΄Π½ΡΠ΅ ΡΠ°ΡΡ ΠΎΠ΄Ρ Π½Π° ΠΏΠ΅ΡΠ΅ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ° Π² Native-Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊΠ΅".
ΠΡ Π·Π°ΠΊΠΎΠ½ΡΠΈΠ»ΠΈ Π½Π°Ρ ΡΠΏΠΈΡΠΎΠΊ. Π’Π΅ΠΏΠ΅ΡΡ, ΠΊΠ°ΠΊ ΠΈ Π΄ΠΎΠ³ΠΎΠ²Π°ΡΠΈΠ²Π°Π»ΠΈΡΡ, Π²ΡΠΏΡΡΠΊΠ°Π΅ΠΌ Π½Π° ΡΡΠ΅Π½Ρ "ΡΡΠ΄ΡΡ".
AOT: "ΠΡΡΠ·ΡΡ, Ρ Π²ΡΡ Π²ΠΈΠ΄Π΅Π». ΠΠΎΠΊΠ° Π²Ρ ΠΏΠΈΡΠ΅ΡΠ΅ ΠΊΠΎΠ΄, Ρ ΡΡΡΠΎΡ Π΅Π³ΠΎ ΠΊΠ°ΡΡΡ. ΠΡΠ»ΠΈ Π²Ρ ΡΠΎΠ±Π»ΡΠ΄Π°Π΅ΡΠ΅ ΡΡΠΈ ΠΏΡΠ°Π²ΠΈΠ»Π°, ΠΌΠΎΠΉ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· ΠΏΡΠΎΡ ΠΎΠ΄ΠΈΡ Π³Π»Π°Π΄ΠΊΠΎ, Π° Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ ΠΏΠΎΠ»ΡΡΠ°Π΅ΡΡΡ Π»ΡΠ³ΠΊΠΈΠΌ ΠΈ Π±ΡΡΡΡΡΠΌ. ΠΠ±ΠΎ Π²ΡΠ΅Ρ Π½Π΅ΠΎΠ΄Π½ΠΎΠ·Π½Π°ΡΠ½ΡΡ ΠΌΠΎΠΌΠ΅Π½ΡΠ°Ρ β Π±ΡΠ΄Ρ ΡΠΎ Π·Π°Π±ΡΡΠ°Ρ ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΡ ΠΈΠ»ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΠΉ ΠΏΡΠΎΠΊΡΠΈ β Ρ ΡΠΎΠΎΠ±ΡΡ Π²Π°ΠΌ Π»ΠΈΠ±ΠΎ Π½Π° ΡΡΠ°ΠΏΠ΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ, Π»ΠΈΠ±ΠΎ ΡΠΆΠ΅ Π² ΠΏΡΠΎΡΠ΅ΡΡΠ΅ ΡΠ°Π±ΠΎΡΡ. ΠΠΎΠΉ Π²Π΅ΡΠ΄ΠΈΠΊΡ ΠΏΡΠΎΡΡ: ΠΏΠΈΡΠΈΡΠ΅ ΠΏΡΠΎΠ·ΡΠ°ΡΠ½ΠΎ, ΠΈ Ρ ΡΠ΄Π΅Π»Π°Ρ Π²Π°ΡΡ Java Π±ΡΡΡΡΠ΅Π΅ Π½Π°ΡΠΈΠ²Π½ΠΎΠ³ΠΎ C++".
| β | ΠΠΎΠ»ΠΎΡΠΎΠ΅ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ | ΠΡΠΎΡΠΈΡ Π΄Π»Ρ JVM (JIT) | ΠΡΠΎΡΠΈΡ Π΄Π»Ρ Native Image (AOT) |
|---|---|---|---|
| 1 | Record Π²ΠΌΠ΅ΡΡΠΎ POJO | ΠΠ³ΡΠ΅ΡΡΠΈΠ²Π½ΡΠΉ ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΠ½Π³ final ΠΏΠΎΠ»Π΅ΠΉ. |
ΠΡΡΡΡΡΠΉ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· Π³ΡΠ°ΡΠ° ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ². |
| 2 | fillInStackTrace(null) | ΠΠΊΠΎΠ½ΠΎΠΌΠΈΡ CPU (Π² 10-50 ΡΠ°Π·) ΠΏΡΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΠΈ Exception. | ΠΠ΅Π½ΡΡΠ΅ Π½Π°ΡΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° Π΄Π»Ρ ΠΎΠ±Ρ ΠΎΠ΄Π° ΡΡΠ΅ΠΊΠ° Π² Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊΠ΅. |
| 3 | Final Π²Π΅Π·Π΄Π΅ | Constant Folding (Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ Π½Π° ΡΡΠ°ΠΏΠ΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ). | ΠΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΠΏΠ°ΠΊΡΠ½ΡΠΉ ΠΈ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·ΡΠ΅ΠΌΡΠΉ ΠΊΠΎΠ΄. |
| 4 | Π‘ΠΌΠ΅ΡΡΡ Π Π΅ΡΠ»Π΅ΠΊΡΠΈΠΈ | ΠΡΡΠΌΡΠ΅ Π²ΡΠ·ΠΎΠ²Ρ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² Π±Π΅Π· ΠΏΠΎΠΈΡΠΊΠ° Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅. | ΠΡΠΈΡΠΈΡΠ½ΠΎ: ΠΠ·Π±Π°Π²Π»ΡΠ΅Ρ ΠΎΡ Π³ΡΠΎΠΌΠΎΠ·Π΄ΠΊΠΈΡ reflect-config.json. |
| 5 | ΠΠΎΡΠΎΡΠΊΠΈΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ | ΠΠ°ΡΠ°Π½ΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ΅ Π²ΡΡΡΠ°ΠΈΠ²Π°Π½ΠΈΠ΅ (inlining). | ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΠ°Π·ΠΌΠ΅ΡΠ° ΠΈΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌΠΎΠ³ΠΎ ΡΠ°ΠΉΠ»Π°. |
| 6 | ΠΡΠ΅Π°Π»Π»ΠΎΠΊΠ°ΡΠΈΡ | ΠΠ΅Π½ΡΡΠ΅ ΠΏΠ°ΡΠ· Garbage Collector Π½Π° "ΠΏΠ΅ΡΠ΅Π΅Π·Π΄Ρ" ΠΌΠ°ΡΡΠΈΠ²ΠΎΠ². | Π‘Π½ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΈΠΊΠΎΠ²ΠΎΠ³ΠΎ ΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΡ RAM. |
| 7 | Long Π²ΠΌΠ΅ΡΡΠΎ BigDecimal | Π Π°Π±ΠΎΡΠ° Π½Π° ΡΠ΅Π³ΠΈΡΡΡΠ°Ρ CPU Π±Π΅Π· Π°Π»Π»ΠΎΠΊΠ°ΡΠΈΠΉ Π² ΠΊΡΡΠ΅. | Π Π°Π΄ΠΈΠΊΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠΌΠ΅Π½ΡΡΠ΅Π½ΠΈΠ΅ ΠΎΠ±ΡΡΠΌΠ° ΠΆΠΈΠ²ΡΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ². |
| 8 | ΠΠΈΠ½ΠΈΠΌΡΠΌ ΠΏΡΠΎΠΊΡΠΈ | ΠΡΠΎΠ·ΡΠ°ΡΠ½ΡΠΉ Π³ΡΠ°Ρ Π²ΡΠ·ΠΎΠ²ΠΎΠ² Π±Π΅Π· ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΏΡΠΎΡΠΎΠ². | ΠΠ΅Π½ΡΡΠ΅ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΎΠΉ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ Π±Π°ΠΉΡ-ΠΊΠΎΠ΄Π°. |
| 9 | Π§ΡΡΠΊΠΈΠ΅ Generics | ΠΡΠΊΠ°Π· ΠΎΡ Π»ΠΈΡΠ½ΠΈΡ
ΠΏΡΠΎΠ²Π΅ΡΠΎΠΊ ΡΠΈΠΏΠΎΠ² (checkcast). |
Π£ΠΏΡΠΎΡΠ΅Π½ΠΈΠ΅ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠΈΠΏΠΈΠ·Π°ΡΠΈΠΈ ΠΏΡΠΈ ΡΠ±ΠΎΡΠΊΠ΅. |
| 10 | CodeGen Π²ΠΌΠ΅ΡΡΠΎ Reflection | Π‘ΠΊΠΎΡΠΎΡΡΡ ΠΏΡΡΠΌΠΎΠ³ΠΎ ΠΏΡΠΈΡΠ²Π°ΠΈΠ²Π°Π½ΠΈΡ a = b. | ΠΡΠ»Π΅Π²ΠΎΠΉ ΠΎΠ²Π΅ΡΡ Π΅Π΄: Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ ΠΌΠ°Π³ΠΈΠΈ Π² ΡΠ°Π½ΡΠ°ΠΉΠΌΠ΅. |
| 11 | Scoped Values | ΠΠ΅Π·ΠΎΠΏΠ°ΡΠ½Π°Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠ° ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ° Π² Virtual Threads. | Π‘ΡΠ°Π±ΠΈΠ»ΡΠ½ΡΠΉ Heap ΠΏΡΠΈ ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π°Ρ ΠΏΠΎΡΠΎΠΊΠΎΠ². |
ΠΠΎΠ»ΠΎΡ AOT (ΡΠΈΠ½Π°Π»ΡΠ½ΡΠΉ Π°ΠΊΠΊΠΎΡΠ΄):
"ΠΠΎΡΠΌΠΎΡΡΠΈΡΠ΅ Π½Π° ΡΡΡ ΡΠ°Π±Π»ΠΈΡΡ. ΠΡΠ»ΠΈ Π²Π°Ρ ΠΏΡΠΎΠ΅ΠΊΡ ΡΠ»Π΅Π΄ΡΠ΅Ρ ΡΡΠΈΠΌ ΠΏΡΠ°Π²ΠΈΠ»Π°ΠΌ, Ρ ΡΠΎΠ±Π΅ΡΡ Π΅Π³ΠΎ Π² Π±ΠΈΠ½Π°ΡΠ½ΠΈΠΊ, ΠΊΠΎΡΠΎΡΡΠΉ ΡΡΠ°ΡΡΡΠ΅Ρ Π·Π° ΠΌΠΈΠ»Π»ΠΈΡΠ΅ΠΊΡΠ½Π΄Ρ. ΠΡΠ»ΠΈ Π½Π΅Ρ β Ρ ΡΠΎΠΎΠ±ΡΡ Π²Π°ΠΌ ΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ "Π³ΡΡΠ·Π½ΠΎΠΉ" ΡΠ΅ΡΠ»Π΅ΠΊΡΠΈΠΈ ΠΈΠ»ΠΈ ΠΏΡΠΎΠΊΡΠΈ, Π»ΠΈΠ±ΠΎ Π½Π° ΡΡΠ°ΠΏΠ΅ ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡΠΈΠΈ, Π»ΠΈΠ±ΠΎ ΠΏΡΡΠΌΠΎ Π² Π»ΠΎΠ± Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΡΠ°Π±ΠΎΡΡ. ΠΡΠ±ΠΎΡ Π·Π° Π²Π°ΠΌΠΈ!"
