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

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

رفتن به کانال در Telegram

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

نمایش بیشتر

📈 تحلیل کانال تلگرام Библиотека Java разработчика

کانال Библиотека Java разработчика (@bookjava) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 10 280 مشترک است و جایگاه 12 030 را در دسته فناوری و برنامه‌ها و رتبه 63 913 را در منطقه روسيا دارد.

📊 شاخص‌های مخاطب و پویایی

از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 10 280 مشترک جذب کرده است.

بر اساس آخرین داده‌ها در تاریخ 05 ژوئن, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر 20 و در ۲۴ ساعت گذشته برابر 0 بوده و همچنان دسترسی گسترده‌ای حفظ شده است.

  • وضعیت تأیید: تأیید نشده
  • نرخ تعامل (ER): میانگین تعامل مخاطب 8.29% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 3.77% واکنش نسبت به کل مشترکان کسب می‌کند.
  • دسترسی پست‌ها: هر پست به طور میانگین 852 بازدید دریافت می‌کند. در اولین روز معمولاً 388 بازدید جمع‌آوری می‌شود.
  • واکنش‌ها و تعامل: مخاطبان به‌طور فعال حمایت می‌کنند؛ میانگین واکنش به هر پست 6 است.
  • علایق موضوعی: محتوا بر موضوعات کلیدی مانند string, интерфейс, строка, boot, api تمرکز دارد.

📝 توضیح و سیاست محتوایی

نویسنده این فضا را محل بیان دیدگاه‌های شخصی توصیف می‌کند:
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP

به لطف به‌روزرسانی‌های پرتکرار (آخرین داده در تاریخ 06 ژوئن, 2026)، کانال همواره به‌روز و دارای دسترسی بالاست. تحلیل‌ها نشان می‌دهد مخاطبان به‌طور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامه‌ها تبدیل کرده‌اند.

10 280
مشترکین
اطلاعاتی وجود ندارد24 ساعت
+27 روز
+2030 روز
آرشیو پست ها
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