uz
Feedback
Библиотека Java разработчика

Библиотека Java разработчика

Kanalga Telegram’da o‘tish

📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP

Ko'proq ko'rsatish

📈 Telegram kanali Библиотека Java разработчика analitikasi

Библиотека Java разработчика (@bookjava) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 10 280 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 12 030-o'rinni va Rossiya mintaqasida 63 913-o'rinni egallagan.

📊 Auditoriya ko‘rsatkichlari va dinamika

невідомо sanasidan buyon loyiha tez o‘sib, 10 280 obunachiga ega bo‘ldi.

05 Iyun, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni 20 ga, so‘nggi 24 soatda esa 0 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.

  • Tasdiqlash holati: Tasdiqlanmagan
  • Jalb etish (ER): Auditoriya o‘rtacha 8.29% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 3.77% ini tashkil etuvchi reaksiyalarni to‘playdi.
  • Post qamrovi: Har bir post o‘rtacha 852 marta ko‘riladi; birinchi sutkada odatda 388 ta ko‘rish yig‘iladi.
  • Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 6 ta reaksiya keladi.
  • Tematik yo‘nalishlar: Kontent string, интерфейс, строка, boot, api kabi asosiy mavzularga jamlangan.

📝 Tavsif va kontent siyosati

Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP

Yuqori yangilanish chastotasi (oxirgi ma’lumot 06 Iyun, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.

10 280
Obunachilar
Ma'lumot yo'q24 soatlar
+27 kunlar
+2030 kunlar
Postlar arxiv
Bulkhead — это паттерн из мира устойчивых систем, цель которого — изолировать сбои в одном компоненте, чтобы они не “затопили” всю систему. Сейчас я покажу вам несколько способов его реализации и подсвечу неочевидный момент при работе с любыми паттернами. 🧠 Концепция: представьте корабль с отсековыми переборками (bulkheads). Если вода просачивается в один отсек, остальные остаются сухими, и судно всё ещё может плыть. В мире Java/Spring это означает: ограничивать ресурсы (пулы потоков, соединения, очереди) для каждого сервиса/метода, чтобы при пике нагрузки или ошибках нагрузка не разошлась по всей системе. 📌 Способ 1: отдельные пул-экзекьюторы

@Configuration
public class BulkheadConfig {
    @Bean("serviceAExecutor")
    public ThreadPoolTaskExecutor serviceAExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(50);
        executor.setThreadNamePrefix("svcA-");
        executor.initialize();
        return executor;
    }
}
В коде контроллера или сервиса указываем:

@Service
public class ServiceA {
    @Autowired @Qualifier("serviceAExecutor")
    private Executor executor;

    public CompletableFuture<String> callExternal() {
        return CompletableFuture.supplyAsync(() -> {
            // долгий/ненадежный вызов
            return externalClient.fetchData();
        }, executor);
    }
}
⚠️ Помните: если пул заполнится, новые задачи будут либо ждать (до исчерпания queueCapacity), либо бросать RejectionException. Настройте RejectedExecutionHandler по необходимости. 📌 Способ 2: Resilience4j Bulkhead (Semaphore vs ThreadPool)

resilience4j.bulkhead.instances:
  myServiceBulkhead:
    maxConcurrentCalls: 5
    maxWaitDuration: 100ms
В сервисе:

@Service
public class MyService {
    private final Bulkhead bulkhead;

    public MyService(BulkheadRegistry registry) {
        this.bulkhead = registry.bulkhead("myServiceBulkhead");
    }

    public String process() {
        return Bulkhead.decorateSupplier(bulkhead, () -> {
            // защищенный вызов
            return externalClient.process();
        }).get();
    }
}
💡 Если поставить maxConcurrentCalls слишком маленьким, часть запросов будет сразу отвергаться с BulkheadFullException. Неочевидный момент: нужно мониторить реальную нагрузку и подбирать значения, а не копировать из гугла. 👉 Также есть аннотационный стиль:

@Bulkhead(name = "myServiceBulkhead", type = Bulkhead.Type.SEMAPHORE)
public String annotatedProcess() { … }
или ThreadPool-вариант:

resilience4j.bulkhead.instances:
  myThreadPoolBulkhead:
    maxThreadPoolSize: 10
    queueCapacity: 20

@Bulkhead(name = "myThreadPoolBulkhead", type = Bulkhead.Type.THREADPOOL)
public CompletionStage<String> asyncProcess() { … }
🧠 Неочевидный момент про паттерны в целом: внедрять Bulkhead “просто потому что модно” — плохо. Паттерн не заменяет мониторинг, трассировку или грамотную архитектуру. Он лишь ограничивает повреждения, но не показывает, где именно проблема. Если вы изолировали компонент в пул, а он всё равно падает, паттерн не скажет “почему”. Всегда сочетайте паттерны с метриками (Micrometer, Prometheus, Grafana) и логированием. 💡 Совет: ▫️Используйте отдельные пулы для медленных операций (например, внешних HTTP-вызовов) и отдельно для CPU-bound задач. ▫️На уровне базы данных тоже можно “бульхедом” выделять разные пулы соединений (например, HikariCP с разными конфигурациями) для тяжелых и легких запросов. ▫️При проектировании микросервисов отдавайте предпочтение Bulkhead на уровне отдельных сервисов: в Kubernetes это можно делать через limits/requests, Horizontal Pod Autoscaling и Circuit Breaker. ⚠️ Предупреждение: перебор с изоляцией приведет к недоиспользованию ресурсов. Если у вас слишком много мелких пулов, а нагрузка неравномерна, часть ресурсов простаивает. Поэтому сначала измерьте нагрузку, а потом разбивайте. 👉@BookJava

👩‍💻 Java — один из самых востребованных языков, но не каждый разработчик умеет использовать его возможности по максимуму. Н
👩‍💻 Java — один из самых востребованных языков, но не каждый разработчик умеет использовать его возможности по максимуму. На курсе «Java Developer. Professional» вы научитесь создавать современные Java-приложения, освоите Spring WebFlux и Kafka, а также разберётесь в работе JVM изнутри. Пройдите тест, проверьте, достаточно ли у вас знаний для обучения на курсе:. 🎁 Дарим промокод, который дает скидку на обучение - JAVA_06 На курсе вас ждёт практическая работа с кодом, детальные разборы, ревью от экспертов и подходы, позволяющие писать эффективный и чистый код. Начните свой путь к уровню Middle+ и используйте Java на 100%. ➡️ Пройти вступительный тест курса: https://vk.cc/cMxZwr Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

30 лет Java: от провалившегося гаджета до фундамента разработки ПО Некоторые языки программирования, например Rust, Go и Type
30 лет Java: от провалившегося гаджета до фундамента разработки ПО Некоторые языки программирования, например Rust, Go и TypeScript, считаются крутыми. Другие, в том числе Cobol и Java, «скучны». Однако пусть Java, которому 23 мая этого года исполнилось тридцать лет, может, и не самый захватывающий язык, он остаётся одним из самых важных. Путь Java начался 23 мая 1995 года, когда его выпустила компания Sun Microsystems. За прошедшее время благодаря удачному видению разработчиков и адаптивности он превратился из нишевого проекта для потребительской электроники в мощный фундамент энтерпрайз-, облачной и веб-разработки. Хоть Java исполнилось тридцать, его история гораздо дольше. Корнями этот язык уходит в 1991 год, когда инженеры Sun Джеймс Гослинг, Майк Шеридан и Патрик Ноутон приступили к созданию языка для интерактивного телевидения и встроенных устройств. Этот проект назвали Green Project. Его цель заключалась не столько в написании нового языка, сколько в создании того, что бы мы сегодня назвали контроллером Интернета вещей. Ещё один разработчик Java Тим Линдхольм, описал его как «своего рода гибрид между КПК и универсальным пультом дистанционного управления». https://habr.com/ru/articles/914970/ original https://www.zdnet.com/article/java-at-30-how-a-language-designed-for-a-failed-gadget-became-a-global-powerhouse/ 👉@BookJava

Optional.stream() появился в Java 9 и позволяет превратить Optional<T> в Stream<T> длины 0 или 1. Зачем это нужно? 📌 Когда применять? ◾️ 🧠 Интеграция с цепочками Stream API: если у вас есть коллекция Optional<T>, можно собрать все непустые значения без дополнительных проверок:

  List<Optional<User>> userOptionals = …;
  List<User> users = userOptionals.stream()
      .flatMap(Optional::stream) // из каждого Optional либо 1 элемент, либо пусто
      .collect(Collectors.toList());
  
Без Optional.stream() пришлось бы делать что-то вроде filter(Optional::isPresent).map(Optional::get). ◾️ 🧠 При операциях над вложенными опционалами: когда в потоке у вас Optional<Something> и вы хотите «сливать», а не оставлять пустые обёртки. 💡 Совет:
Если вы строите конвейер обработки данных, а на каком-то шаге может не быть значения — Optional.stream() поможет аккуратно пропустить «пустышки» и не ломать последующие операции.
⚠️ Но вот в чём «подводные камни» и почему нельзя злоупотреблять: 1. Потеря явности ◾️ Когда вы где-то просто хотите проверить: есть ли значение в Optional, — использование stream() создаёт впечатление, что у вас реально коллекция элементов, хотя всего лишь 1 или 0. Для простых случаев ifPresent(), map(), orElse() читается понятнее.

   // Менее канонично:
   optionalValue.stream().forEach(v -> doSomething(v));
   // Лучше:
   optionalValue.ifPresent(v -> doSomething(v));
   
2. Ненужные накладные расходы ◾️ Каждый вызов Optional.stream() создаёт объект стрима и небольшую внутреннюю структуру, что на горячем участке кода (в tight loop) может сказаться на производительности. Если вместо него можно обойтись map().orElse(), задумайтесь о легковесном варианте. 3. Скрытые баги ◾️ Если вы по ошибке используете Optional.stream() в одиночном случае (не в контексте объединения множества опционалов), код может стать менее очевидным. Например:

   // Что тут происходит?
   Stream.of(opt1, opt2, opt3)
         .flatMap(Optional::stream)
         .findFirst();
   
Казалось бы, надо искать первый непустой, но читающий код может не сразу понять логику: а вдруг нужно просто взять любое значение, а не первой в списке? Лушче явно:

   Optional<User> result = opt1.isPresent() ? opt1
       : opt2.isPresent() ? opt2
       : opt3;
   
4. Лишняя сложность ◾️ В ситуациях, когда Optional появляется из map/filter в одном стриме, а потом вы вновь оборачиваете результат в Optional, лучше сразу строить последовательность через flatMap и filter без промежуточных Optional. 💡 Пример «полезного» применения:

List<Order> orders = getOrders();

// Для каждого заказа пытаемся получить пользователя из БД,
// но он может быть не найден (Optional<User>).
List<Optional<User>> maybeUsers = orders.stream()
    .map(o -> userRepository.findById(o.getUserId()))
    .toList();

// Теперь формируем список уже «существующих» юзеров:
List<User> users = maybeUsers.stream()
    .flatMap(Optional::stream)
    .collect(Collectors.toList());
Здесь Optional.stream() полностью оправдан: сразу избавляемся от «пустых» опционалов. 💡 Анти-паттерн:
Не используйте Optional.stream() внутри метода, который ожидает ровно одно значение или бросает исключение, если опционал пуст.

// Плохо:
User user = optionalUser.stream()
    .findFirst()
    .orElseThrow(() -> new NotFoundException("User not found"));

// Лучше так:
User user = optionalUser
    .orElseThrow(() -> new NotFoundException("User not found"));
В первом случае мы заводим стрим без смысла, во втором — прямой и понятный код. Итого: ◾️ 🧠 Используйте Optional.stream() только когда действительно нужно объединить несколько Optional-ов в один Stream и пропустить пустые. ◾️ ⚠️ В одиночных сценариях проверки и извлечения значения он избыточен и даже снижает читабельность и производительность. 👉@BookJava

🔍Тестовое собеседование с Java-разработчиком из Т1 Иннотех уже завтра 4 июня(уже завтра!) в 19:00 по мск приходи онлайн на о
🔍Тестовое собеседование с Java-разработчиком из Т1 Иннотех уже завтра 4 июня(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Илья Аров, старший разработчик в Т1, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Илья будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Илье Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqvL6bDw

🧠 Конфигурация Spring Boot 3 через record и @ConstructorBinding Вместо традиционных @Data + пустого конструктора можно сразу использовать Java 17 record для настройки свойств: 📌 Почему это полезно? 🔴Полная иммутабельность: поля конфигов больше нельзя случайно перезаписать. 🔴Минимум «шаблонного» кода: не нужны геттеры, сеттеры, toString(), equals() и т.д. 🔴Чёткая связь с Java 17+ и актуальными best practices. 💡 Как сделать: 1. Подключаем зависимость:

   <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-configuration-processor</artifactId>
     <optional>true</optional>
   </dependency>
   
Это нужно, чтобы IDE и Spring метаинфу подхватили. 2. Создаём record с аннотацией:

   import org.springframework.boot.context.properties.ConfigurationProperties;
   import org.springframework.boot.context.properties.ConstructorBinding;

   @ConstructorBinding
   @ConfigurationProperties(prefix = "app.mail")
   public record MailProperties(
       String host,
       int port,
       String username,
       String password
   ) {}
   
3. Регистрируем бин в Spring:

   import org.springframework.boot.context.properties.EnableConfigurationProperties;
   import org.springframework.context.annotation.Configuration;

   @Configuration
   @EnableConfigurationProperties(MailProperties.class)
   public class AppConfig { }
   
4. Конфигурируем в application.yml (или .properties):

   app:
     mail:
       host: smtp.example.com
       port: 587
       username: user@example.com
       password: secret123
   
⚠️ Обратите внимание: 🔴Без @ConstructorBinding Spring не сможет смотать значения в record’ы. 🔴Уберите все сеттеры и по умолчанию конструктор генерируется автоматически. 🔴Если вам нужна валидация свойств, добавьте @Validated и JSR-303 аннотации (@NotNull, @Min и т.д.). 🧠 Что получилось? 🔴Минимум «мусора» в коде: один блок record заменил класс с 4 полями, геттерами и конструктором. 🔴Полная типобезопасность и поддержка автокомплита при обращении к полям. 🔴Быстрый переход на Java 17+ подходы без потери функциональности. 💡 Дополнительный лайфхак: Если вам нужно разделить конфиги по окружениям (dev/prod), просто создайте два record’а с разными префиксами или используйте @Profile. В Spring Boot 3 этот подход «из коробки» работает наилучшим образом. 👉@BookJava

Релиз через два дня. Код готов. Почти... Остались тесты. Ну, точнее — покрытие. Потому что QA уже дышит в затылок, а ты сидиш
Релиз через два дня. Код готов. Почти... Остались тесты. Ну, точнее — покрытие. Потому что QA уже дышит в затылок, а ты сидишь и выбираешь: спать или корпеть до утра. Explyt Test умеет создавать тесты под твой код — сам. Быстро. В IDE. Без плясок. Хочешь, чтобы релиз прошёл, а не пролетел? Попробуй бесплатно! 👉 explyt.ai

В асинхронных или веб-сервисах на реактиве нужно быть осторожным: SecurityContext не “переходит” автоматически в новые потоки. Для этого используют SecurityContextRepository и специальные методы в WebFlux. ⚠️ Важно: не храните SecurityContext в сессии, если у вас stateless-приложение (REST API). Вместо сессии используйте JWT или OAuth 2.0. 🧠 5. Авторизация: FilterSecurityInterceptor & AccessDecisionManager FilterSecurityInterceptor запускается в конце цепочки фильтров и проверяет доступ к URL. Он запрашивает у SecurityMetadataSource список необходимых ролей для данного эндпоинта (Spring на основании @PreAuthorize, HttpSecurity конфигурации или XML). Затем передаёт дело в AccessDecisionManager (по умолчанию AffirmativeBased), который опрашивает список AccessDecisionVoter (например, RoleVoter для проверок ролей, WebExpressionVoter для SpEL).

FilterSecurityInterceptor
   └─> SecurityMetadataSource (что нужно: ROLE_ADMIN)
   └─> AccessDecisionManager.vote() 
       ├─ RoleVoter.vote() → совпадает?
       └─ WebExpressionVoter.vote() → SpEL-выражения?
Если хотя бы один голос “grant”, AffirmativeBased отпускает запрос (по умолчанию). Можно менять стратегию на Consensus или Unanimous. 💡 Трюк: чтобы локально протестировать SecurityContext, можно в тестах использовать аннотацию @WithMockUser(roles = "ADMIN") и проверять, что нужный эндпоинт доступен. 🧠 6. Аннотации & Method Security Помимо URL-уровня, есть методная проверка:

@EnableMethodSecurity // (Spring Boot 3+) вместо @EnableGlobalMethodSecurity
public class SecurityConfig { ... }

// Где-то в сервисе:
@PreAuthorize("hasRole('ADMIN') and #id == principal.id")
public void deleteUser(Long id) { ... }
* 📌 @PreAuthorize / @PostAuthorize / @Secured / @RolesAllowed — все используют тот же механизм Voter’ов, но проверяют уже на методах сервиса. * 💡 Совет: включайте методную безопасность только там, где действительно нужна тонкая грануляция. 🧠 7. Хранение паролей & PasswordEncoder С Java 17+ используйте PasswordEncoder с алгоритмами Argon2 или BCrypt:

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12);
}
⚠️ Никогда не храните пароли в открытом виде и не используйте MD5/SHA-1 — они считаются небезопасными. 🧠 8. Stateless vs Stateful * Stateful (Сессии): Spring создаёт HTTP-сессию, а SecurityContextPersistenceFilter хранит контекст в сессии. Удобно для монолитов с классическим web-приложением. * Stateless (JWT/OAuth2): убираем SessionCreationPolicy.STATELESS, используем BearerTokenAuthenticationFilter, аутентификация и авторизация проверяются по JWT в каждом запросе. 💡 Современный стек (Spring Boot 3+): 1. Настраиваем SecurityFilterChain с oauth2ResourceServer().jwt(). 2. Подключаем spring-boot-starter-oauth2-resource-server. 3. Указываем issuer-uri или jwk-set-uri в application.yml.

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://keycloak.example.com/realms/myrealm
🧠 9. Подпись запросов & CSRF * По умолчанию CSRF включён для “форменных” запросов (POST, PUT, DELETE). Для stateless-API его обычно отключают:

  http.csrf().disable();
  
* Если используете формы, не забудьте добавить в шаблон:

  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
  
⚠️ Внимание: не отключайте CSRF, если ваше приложение использует сессии и cookie на фронтенде! 💡 Совет по отладке: включите логирование фильтров:

logging.level.org.springframework.security=DEBUG
Тогда в логах вы увидите, как проходит запрос через каждый фильтр и где происходит отказ. 👉@BookJava

📌 Spring Security: основная архитектура 🧠 1. SecurityFilterChain & FilterChainProxy Spring Security строит всё вокруг цепочки фильтров (FilterChainProxy). При запросе к приложению запрос проходит через набор фильтров, каждый из которых отвечает за свой кусок логики: * ⚙️ ChannelProcessingFilter – перенаправление на HTTPS, если нужно. * ⚙️ SecurityContextPersistenceFilter – загружает/сохраняет SecurityContext (где хранится Authentication). * ⚙️ UsernamePasswordAuthenticationFilter – обрабатывает форму логина (если вы используете formLogin). * ⚙️ BasicAuthenticationFilter – поддерживает HTTP Basic (для REST). * ⚙️ BearerTokenAuthenticationFilter (Spring Boot 3+) – для JWT/OAuth2 Bearer-токенов. * ⚙️ ExceptionTranslationFilter – перехватывает AccessDeniedException и AuthenticationException, перенаправляет на страницу логина или возвращает 401. * ⚙️ FilterSecurityInterceptor – проверяет, есть ли у аутентифицированного пользователя разрешение (ROLE_*) для доступа к ресурсу. Каждый фильтр решает конкретную задачу, и порядок важен: если, например, фильтр авторизации (FilterSecurityInterceptor) стоит раньше, чем фильтр аутентификации, вы получите неожиданный отказ. 💡 Современный подход (Spring Boot 3+):

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .csrf().disable()
      .authorizeHttpRequests(auth -> auth
          .requestMatchers("/public/**").permitAll()
          .anyRequest().authenticated()
      )
      .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
      .oauth2ResourceServer(oauth2 -> oauth2.jwt()); // JWT из OIDC/JWK  
    return http.build();
}
Таким образом вы сами управляете порядком фильтров и включаете только нужные. 🧠 2. AuthenticationManager & ProviderManager Когда UsernamePasswordAuthenticationFilter (или другой аутентификатор) получает учётные данные, он создает UsernamePasswordAuthenticationToken с неверифицированными (unauthenticated) флагом. Затем передаёт этот токен в AuthenticationManager:

UsernamePasswordAuthenticationFilter → AuthenticationManager.authenticate()
AuthenticationManager по умолчанию — это ProviderManager, который хранит список AuthenticationProvider (например, DaoAuthenticationProvider для UserDetailsService или JwtAuthenticationProvider для токенов). Каждый Provider пытается аутентифицировать токен, и если успешно, возвращает уже аутентифицированный Authentication с authorities. 📌 Совет: если нужно добавить кастомную проверку (например, MFA), реализуйте свой AuthenticationProvider и зарегистрируйте его перед DaoAuthenticationProvider. 🧠 3. UserDetailsService & UserDetails DaoAuthenticationProvider опирается на UserDetailsService (или ReactiveUserDetailsService в WebFlux), чтобы получить UserDetails (имя, пароль, роли, статус аккаунта). В Java 17+ можно пользоваться Map.of(...) или List.of(...), но в реальных проектах лучше хранить в БД через JPA/Hibernate.

@Service
public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository repo;
    @Override
    public UserDetails loadUserByUsername(String username) {
        UserEntity user = repo.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("User not found"));
        return User.withUsername(user.getUsername())
                   .password(user.getPassword())
                   .authorities(user.getRoles().toArray(new String[0]))
                   .accountLocked(!user.isAccountNonLocked())
                   .build();
    }
}
🧠 4. SecurityContext & SecurityContextHolder После успешной аутентификации фильтр устанавливает SecurityContext в SecurityContextHolder. По умолчанию используется стратегия MODE_THREADLOCAL, т.е. контекст привязан к текущему потоку.

SecurityContextHolder.getContext().setAuthentication(authenticatedToken);

«Я слышу свой код»: как работает Java-программист, потерявший зрение Константин Евтеев собирает Java-код с помощью диктора NV
«Я слышу свой код»: как работает Java-программист, потерявший зрение Константин Евтеев собирает Java-код с помощью диктора NVDA, редактирует его в Блокноте и передает на Linux по SSH через самописные bash-скрипты. После потери зрения он не потерял интереса к жизни и желания быть полезным и выстроил собственную инженерную экосистему: оглавления по строкам .txt-файлами, навигация по main и маленьким методам, отладка на слух. https://habr.com/ru/companies/axiomjdk/articles/913748/ 👉@BookJava

🧠 Чем Spring Native Image отличается от обычного Spring-приложения? 📌 Обычный Spring: * Запускается на JVM, динамически заг
🧠 Чем Spring Native Image отличается от обычного Spring-приложения? 📌 Обычный Spring: * Запускается на JVM, динамически загружает классы, использует рефлексию. * Медленный старт (секунды), выше потребление памяти. * Подходит для сложной логики с динамическим поведением (настройки, рефлексия, прокси). 📌 Spring Native Image (GraalVM): * Компиляция в нативный бинарник. * ⚡️ Мгновенный старт (миллисекунды), низкое потребление памяти. * Отсутствие динамики: ограничения в рефлексии, прокси и динамической загрузке. 💡 Когда что использовать? * Native Image — идеален для микросервисов и Serverless-приложений. * Обычный JVM Spring — когда важна максимальная гибкость и динамика. ⚠️ Помни, что Native Image требует больше усилий по настройке и ограничений на библиотеки. 👉@BookJava

🚀 Подборка Telegram каналов для программистов Системное администрирование, DevOps 📌 https://t.me/bash_srv Bash Советы https://t.me/win_sysadmin Системный Администратор Windows https://t.me/sysadmin_girl Девочка Сисадмин https://t.me/srv_admin_linux Админские угодья https://t.me/linux_srv Типичный Сисадмин https://t.me/devopslib Библиотека девопса | DevOps, SRE, Sysadmin https://t.me/linux_odmin Linux: Системный администратор https://t.me/devops_star DevOps Star (Звезда Девопса) https://t.me/i_linux Системный администратор https://t.me/linuxchmod Linux https://t.me/sys_adminos Системный Администратор https://t.me/tipsysdmin Типичный Сисадмин (фото железа, было/стало) https://t.me/sysadminof Книги для админов, полезные материалы https://t.me/i_odmin Все для системного администратора https://t.me/i_odmin_book Библиотека Системного Администратора https://t.me/i_odmin_chat Чат системных администраторов https://t.me/i_DevOps DevOps: Пишем о Docker, Kubernetes и др. https://t.me/sysadminoff Новости Линукс Linux 1C разработка 📌 https://t.me/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С https://t.me/DevLab1C 1С:Предприятие 8 https://t.me/razrab_1C 1C Разработчик https://t.me/buh1C_prog 1C Программист | Бухгалтерия и Учёт https://t.me/rabota1C_rus Вакансии для программистов 1С Программирование C++📌 https://t.me/cpp_lib Библиотека C/C++ разработчика https://t.me/cpp_knigi Книги для программистов C/C++ https://t.me/cpp_geek Учим C/C++ на примерах Программирование Python 📌 https://t.me/pythonofff Python академия. https://t.me/BookPython Библиотека Python разработчика https://t.me/python_real Python подборки на русском и английском https://t.me/python_360 Книги по Python Java разработка 📌 https://t.me/BookJava Библиотека Java разработчика https://t.me/java_360 Книги по Java Rus https://t.me/java_geek Учим Java на примерах GitHub Сообщество 📌 https://t.me/Githublib Интересное из GitHub Базы данных (Data Base) 📌 https://t.me/database_info Все про базы данных Мобильная разработка: iOS, Android 📌 https://t.me/developer_mobila Мобильная разработка https://t.me/kotlin_lib Подборки полезного материала по Kotlin Фронтенд разработка 📌 https://t.me/frontend_1 Подборки для frontend разработчиков https://t.me/frontend_sovet Frontend советы, примеры и практика! https://t.me/React_lib Подборки по React js и все что с ним связано Разработка игр 📌 https://t.me/game_devv Все о разработке игр Библиотеки 📌 https://t.me/book_for_dev Книги для программистов Rus https://t.me/programmist_of Книги по программированию https://t.me/proglb Библиотека программиста https://t.me/bfbook Книги для программистов БигДата, машинное обучение 📌 https://t.me/bigdata_1 Big Data, Machine Learning Программирование 📌 https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций https://t.me/rust_lib Полезный контент по программированию на Rust https://t.me/golang_lib Библиотека Go (Golang) разработчика https://t.me/itmozg Программисты, дизайнеры, новости из мира IT https://t.me/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 https://t.me/nodejs_lib Подборки по Node js и все что с ним связано https://t.me/ruby_lib Библиотека Ruby программиста https://t.me/lifeproger Жизнь программиста. Авторский канал. QA, тестирование 📌 https://t.me/testlab_qa Библиотека тестировщика Шутки программистов 📌 https://t.me/itumor Шутки программистов Защита, взлом, безопасность 📌 https://t.me/thehaking Канал о кибербезопасности https://t.me/xakep_2 Хакер Free Книги, статьи для дизайнеров 📌 https://t.me/ux_web Статьи, книги для дизайнеров Математика 📌 https://t.me/Pomatematike Канал по математике https://t.me/phis_mat Обучающие видео, книги по Физике и Математике https://t.me/matgeoru Математика | Геометрия | Логика Excel лайфхак📌 https://t.me/Excel_lifehack https://t.me/mir_teh Мир технологий (Technology World) Вакансии 📌 https://t.me/sysadmin_rabota Системный Администратор https://t.me/progjob Вакансии в IT

Как не завалить приложение из-за N+1 запросов в Hibernate 🧨 N+1 проблема — больной зуб почти любого Java-разработчика. Hiber
Как не завалить приложение из-за N+1 запросов в Hibernate 🧨 N+1 проблема — больной зуб почти любого Java-разработчика. Hibernate делает жизнь проще, пока не сталкиваешься с этим 👻 📌 Суть проблемы Допустим, у тебя есть сущности User и связанные с ними сущности Order. При запросе пользователей:

List<User> users = userRepository.findAll(); // Один запрос
for(User user : users) {
    List<Order> orders = user.getOrders(); // +1 запрос на каждого пользователя!
}
Если пользователей 1000, то будет 1 + 1000 SQL-запросов. Это убийственно для производительности ⚠️ 🛠 Как решить? 💡 Вариант 1: JOIN FETCH Самый быстрый и простой путь — сразу подтянуть связанные сущности:

@Query("SELECT u FROM User u JOIN FETCH u.orders")
List<User> findAllWithOrders();
✅ Всего один SQL-запрос ❌ Может привести к дублированию строк, если связей много и они сложные 💡 Вариант 2: Entity Graph (Spring Data JPA) Entity Graph — более гибкий подход:

@EntityGraph(attributePaths = {"orders"})
List<User> findAll();
✅ Удобно и понятно, нет дублей ✅ Можно легко настраивать под конкретный запрос 💡 Вариант 3: Batch fetching (настройка Hibernate)

spring.jpa.properties.hibernate.default_batch_fetch_size=20
Hibernate будет автоматически загружать связанные сущности пачками. ✅ Просто настроить и сразу эффект ❌ Всё равно несколько запросов, хотя и пачками 🧠 Когда что использовать? ▫️ JOIN FETCH — когда связи простые, а данных немного. ▫️ Entity Graph — если нужна гибкость и удобство. ▫️ Batch fetching — когда настроить проще, чем переписывать код. Не забывай проверять SQL-запросы в логах и профилировать приложение 🔥 👉@BookJava

🗑 Понимание различных сборщиков мусора в Java 🔵 Serial Garbage Collector: Лучший вариант для однопоточных приложений с небольшими кучами. Он использует один поток для выполнения как малых, так и больших сборок мусора, что приводит к значительным паузам, но минимальной нагрузке на систему. 🔵 Parallel Garbage Collector: Подходит для приложений с высокими требованиями к пропускной способности. Использует несколько потоков для выполнения как малых, так и больших сборок мусора, уменьшая время пауз, но при этом увеличивая использование CPU. 🔵 Concurrent Mark-Sweep (CMS) Garbage Collector: Разработан для минимизации пауз за счёт выполнения основной части работы по сборке мусора параллельно с выполнением приложений. Подходит для приложений, где критически важна низкая задержка. 🔵 G1 Garbage Collector: Сбалансированный сборщик мусора, который стремится обеспечить предсказуемое время пауз, разделяя кучу на регионы и выполняя сборку мусора поэтапно. Является хорошим выбором по умолчанию для большинства приложений. 🔵 Z Garbage Collector и Shenandoah: Сборщики мусора с ультранизкой задержкой, разработанные для работы с большими кучами. Основная часть работы по сборке мусора выполняется параллельно, что позволяет минимизировать время пауз даже при очень больших кучах. 👉@BookJava

Серия статей: «Дюк, вынеси мусор!» Все, что нужно знать о сборке мусора в Java 🔹 Если работа с JVM для тебя не просто слова,
Серия статей: «Дюк, вынеси мусор!» Все, что нужно знать о сборке мусора в Java 🔹 Если работа с JVM для тебя не просто слова, а параметры вроде Xmx и Xms ты прописываешь с закрытыми глазами, самое время разобраться, что же реально происходит с памятью в Java и как новые сборщики мусора могут повлиять на производительность твоего приложения. 🗂 В этой серии — подробный разбор всех современных GC, доступных в Java HotSpot VM: от базовых до самых продвинутых. Для каждого — объяснение принципов, сценарии применения, плюсы и минусы, а также практические советы по настройке. Список статей: 1️⃣ Введение 2️⃣ Serial GC и Parallel GC 3️⃣ CMS и G1 4️⃣ ZGC 5️⃣ Epsilon GC 6️⃣ Shenandoah GC 👉@BookJava

👩‍💻 Хотите выйти за пределы стандартных подходов в Java-разработке? Разобраться в JVM, многопоточности и современных фреймв
👩‍💻 Хотите выйти за пределы стандартных подходов в Java-разработке? Разобраться в JVM, многопоточности и современных фреймворках? 🔥 Актуальное обучение, курс «Java Developer. Professional» — это 96 часов практики, детальный разбор технологий, код-ревью от опытных экспертов и работа с Spring WebFlux, Kafka, Kubernetes. После обучения вы сможете разрабатывать сложные Java-приложения уровня Middle+, понимать работу JVM изнутри и писать чистый, оптимизированный код. 🎁 Дарим промокод, который дает скидку на обучение - JAVA_06 ➡️ Пройдите вступительное тестирование и получите скидку: https://vk.cc/cMonpN Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

🧠 Сейчас расскажу о распределённых транзакциях в Java и почему их стоит использовать с осторожностью. Когда твое приложение
🧠 Сейчас расскажу о распределённых транзакциях в Java и почему их стоит использовать с осторожностью. Когда твое приложение работает с несколькими источниками данных (например, двумя базами или базой + очередью), часто появляется соблазн обернуть всё в одну большую транзакцию с помощью JTA (Java Transaction API) и XA-ресурсов. Но на практике это почти всегда антипаттерн. 📌 Почему? * XA-транзакции медленные и сложно отлаживаются. * Они ломают горизонтальное масштабирование: один сбой — откат по всем участникам. * Могут приводить к блокировкам и deadlock-ам, если инфраструктура нестабильна. 💡 Современные альтернативы: 1. Transaction outbox pattern — сначала пишем событие/задачу в outbox-таблицу в той же БД, где меняем данные, и только потом публикуем во внешний сервис. 2. Event sourcing — строим архитектуру так, чтобы любые изменения происходили через событийную модель (и проще компенсировать сбои). 3. Idempotency & retries — делаем операции идемпотентными и безопасными к повтору. ⚠️ Не используешь JTA без реальной необходимости. Spring Boot 3+ по умолчанию уже не настраивает JTA — и правильно делает. Если всё же нужен XA: * Используй Atomikos, Narayana или Bitronix — это современные провайдеры. * Но всегда сначала подумай: "Могу ли я упростить архитектуру и уйти от XA?" Пример из кода на Spring Boot:

// НЕ рекомендуется:
@EnableTransactionManagement
public class Config {
  @Bean
  public JtaTransactionManager transactionManager() {
      return new JtaTransactionManager();
  }
}

// Лучше outbox + отдельный publisher
🧠 В 99% случаев проще и надёжнее строить архитектуру вокруг событий и простых локальных транзакций, чем бороться с XA. 👉@BookJava

🧠 Сегодня разберём Saga — паттерн, который часто всплывает на собеседованиях уровня сеньор, особенно если речь о микросервис
🧠 Сегодня разберём Saga — паттерн, который часто всплывает на собеседованиях уровня сеньор, особенно если речь о микросервисах. 📌 Зачем нужна Saga? Когда нужно выполнить бизнес-операцию, затрагивающую несколько микросервисов, важно обеспечить целостность данных. Классические транзакции (@Transactional) тут не подходят — нет распределённого ACID. Saga решает эту проблему через последовательность локальных транзакций с возможностью отката (compensation). 💡 Виды Saga 1. Choreography Нет единого оркестратора. Каждый сервис реагирует на события предыдущих через очередь (Kafka, RabbitMQ). * Простой flow * Меньше точек отказа 2. Orchestration Есть выделенный "оркестратор", который координирует выполнение саги, рассылая команды сервисам. * Более явный контроль * Лучше трассировка ⚖️ Плюсы * Обеспечивает согласованность между сервисами * Высокая отказоустойчивость: каждый шаг можно компенсировать * Гибкость — легко расширять и модифицировать бизнес-логику ⚠️ Минусы * Сложнее реализовать, чем простые транзакции * Не моментальная консистентность — возможны временные аномалии * Нужно проектировать compensating transactions для каждого шага * Тяжело тестировать крайние случаи и "сорванные" шаги 🔁 Альтернативы * Distributed Transactions (XA, 2PC) — редко используются из-за сложности и слабой поддержки в современных cloud-системах. * Event Sourcing — другой паттерн работы с изменениями, но сложнее для чтения. * Idempotency + Retry — иногда достаточно, если бизнес-процесс допускает. 💡 Совет: для большинства бизнес-операций с межсервисным взаимодействием, где требуется отмена — Saga остаётся самым практичным выбором. В Spring есть библиотека Axon Framework, также стоит посмотреть на Camunda. 👉@BookJava

Ищем Java-разработчика в команду онлайн-рекомендаций AI VK 🤖 Будем вместе разрабатывать высоконагруженные микросервисы на Ja
Ищем Java-разработчика в команду онлайн-рекомендаций AI VK 🤖 Будем вместе разрабатывать высоконагруженные микросервисы на Java. Кроме кода доверим коллеге принимать архитектурные и технические решения, гибко настраивать ML-эксперименты и рекомендательный пайплайн. Если любите технически сложные задачи и хотите работать с большими данными, ждём ваше резюме на сайте VK Team!

🧠 Как быстро написать компаратор в Java и не забыть про null Часто нужно сортировать коллекции по какому-то полю. Вместо ста
🧠 Как быстро написать компаратор в Java и не забыть про null Часто нужно сортировать коллекции по какому-то полю. Вместо старых анонимных классов используем лямбды и статические методы из Comparator:

List<User> users = ...;

users.sort(Comparator
    .comparing(User::getName, Comparator.nullsLast(String::compareToIgnoreCase))
    .thenComparingInt(User::getAge)
);
📌 comparing — сравнивает по полю (например, name). 📌 nullsLast или nullsFirst — удобно обрабатывать возможные null. 📌 thenComparingInt — дополнительная сортировка (например, по возрасту). 💡 Такой подход краткий, читабельный и отлично работает с любыми полями, даже если они могут быть null. ⚠️ Никогда не забывай про null, особенно если сортируешь данные из БД или внешних источников. Ошибка NullPointerException во время сортировки может неожиданно прилететь в проде. 👉@BookJava