25698
Все самое полезное для Java-разработчика в одном канале. Список наших каналов: https://t.me/proglibrary/9197 Обратная связь: @proglibrary_feedback_bot По рекламе: @proglib_adv Прайс: @proglib_advertising
📈 Продвинутая Map
Если ты хоть раз создавал Map<String, List<String>>, то пост для тебя.
Признай, каждый когда-нибудь писал:
Map<String, List<String>> userTags = new HashMap<>();
userTags.computeIfAbsent("user123", k -> new ArrayList<>()).add("premium");
userTags.computeIfAbsent("user123", k -> new ArrayList<>()).add("verified");
if (!userTags.containsKey("user123")) {
userTags.put("user123", new ArrayList<>());
}
userTags.get("user123").add("premium");MultiValuedMap<String, String> userTags = new ArrayListValuedHashMap<>();
userTags.put("user123", "premium");
userTags.put("user123", "verified");
userTags.put("user123", "early-adopter");
// Получаем все теги разом
Collection<String> tags = userTags.get("user123");
// [premium, verified, early-adopter]
multiMap.put("key", "value1");
multiMap.put("key", "value2"); // не перезатирает предыдущее значениеmultiMap.putAll("user456", Arrays.asList("admin", "moderator"));multiMap.containsMapping("user123", "premium"); // true/falsemultiMap.removeMapping("user123", "premium");Collection<String> allTags = multiMap.values();
// все значения из всех ключей
⚙️ YAML vs Properties: что выбрать для Spring Boot конфигурации?
Недавно в очередной раз столкнулся с холиваром: "Зачем ты переписал properties в yaml?" Давайте разбираться.
🔹 Properties — старая гвардия
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=admin
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: admin
password: secret
jpa:
hibernate:
ddl-auto: validate
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
🎮 Инструментарий разработчика
Собрали самые популярные и эффективные инструменты на все случаи жизни.
💬 Какие инструменты используете в повседневной работе?
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
Java в Enterprise + AI Agents = Мощный стек
Крупный бизнес 2026 года активно внедряет AI, и ему нужны надёжные решения. Как встроить LLM-агента в экосистему Spring? Как обеспечить безопасность данных?
На курсе мы учим архитектурному подходу. Мы разбираем паттерны построения агентов, которые можно реализовать на любом языке (в том числе через Spring AI), или интегрировать Python-микросервисы в вашу Java-инфраструктуру. Реальные кейсы, разбор ошибок и фокус на Enterprise.
Ключевые темы:
— Паттерны надёжности (Retry, Fallback, Circuit Breaker) при работе с LLM.
— Интеграция с корпоративными Knowledge Base (RAG).
— Безопасность и контроль доступа (RBAC) в агентных системах.
Освоить проектирование AI-систем
🔧 Jackson: безопасная десериализация в Spring Boot
Дефолтные настройки Jackson молча игнорируют неизвестные поля в JSON и используют небезопасные типы. В production это маскирует ошибки контрактов API и открывает векторы атак через полиморфную десериализацию.
🔹 Решение
▪️ Настройка через application.yml
spring:
jackson:
deserialization:
fail-on-unknown-properties: true # фейлим на лишние поля
fail-on-null-for-primitives: true
serialization:
write-dates-as-timestamps: false # ISO-8601 вместо timestamp
fail-on-empty-beans: false
default-property-inclusion: non_null # не сериализуем null
mapper:
default-view-inclusion: true
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// Безопасность
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.activateDefaultTyping(
BasicPolymorphicTypeValidator.builder()
.allowIfBaseType(Object.class)
.build(),
ObjectMapper.DefaultTyping.NON_FINAL
);
// Даты
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// Null handling
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mapper;
}
}
@JsonIgnoreProperties(ignoreUnknown = false) // строго
public record UserDto(
@NotNull String username,
@JsonProperty("email_address") String email,
@JsonFormat(pattern = "yyyy-MM-dd") LocalDate birthDate
) {}
💭 Микросервисы: Spring Cloud
Когда проект разрастается до десятков микросервисов, появляется ряд вопросов, которые не возникают, если у тебя монолит:
— Как сервису А узнать, где сейчас живёт сервис Б (тем более, если адреса постоянно меняются)?
— Как не утонуть в километрах кода для HTTP-запросов?
— Как фронтенду работать с этой кучей сервисов?
Для этого есть три главных инструмента.
1️⃣ Eureka: телефонная книга (Service Discovery)
В облаке сервисы постоянно перезапускаются, меняют IP-адреса и порты. Хардкодить http://localhost:8082 не вариант.
Eureka Server работает как справочная служба
🔹 При старте каждый сервис стучится в Eureka: «Я на связи, вот мой адрес».
🔹 Когда сервису А нужно достучаться до Б, он обращается к Eureka: «Подскажи, где сейчас сервис Б».
Нужно добавить аннотацию @EnableDiscoveryClient для работы Eureka. Сервисы будут находить друг друга по имени, а не по IP.
2️⃣ OpenFeign: инструмент для связи
Для отправки запросов между сервисами можно использовать RestTemplate. Но код получается довольно громоздким и не типизированным.
Вместо этого можно использовать Feign. Он позволяет вызывать удаленный REST-сервис так, будто это обычный метод интерфейса. А вся реализация генерируется под капотом.
@FeignClient(name = "account-service") // Имя сервиса в Eureka
public interface AccountClient {
@GetMapping("/account/{userId}")
List<Account> getAccount(@PathVariable Long userId);
}
// Использование в сервисе:
List<Account> accounts = accountClient.getAccount(13L);
🐸 Библиотека джависта
#DevLife
❓ Spring AI в продакшене
Наш подписчик спрашивает:
Вопрос к сообществу. Начальство загорелось идеей прикрутить к проекту AI. Проект на Spring Boot 3, Java 21. Юзал кто Spring AI? Подводные камни, баги, альтернативы?
Фреймворк на первый взгляд удобный, но я наткнулся на статью, где разраб жалуется, что между версиями меняются даже названия пакетов. Код с октября уже не работает. Примеры в интернете все разные в зависимости от даты написания.
❓ Что делает параметр readOnly = true у @Transactional?
readOnly = true — это подсказка для оптимизации, а не строгое ограничение.
Что происходит:
— Hibernate может пропустить flush (не синхронизировать изменения с БД)
— БД может оптимизировать запрос, не создавая блокировки
— некоторые драйверы могут использовать read-only соединения
Важно: это не запрещает изменения программно. Можно вызвать save(), но изменения не гарантированно применятся. Это именно hint для оптимизации.
🐸 Библиотека собеса по Java
#spring
Шаг 3: JWT Authentication Filter
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain
) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
final String jwt = authHeader.substring(7);
final String username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
@ConfigurationЧитать полностью…
@RequiredArgsConstructor
public class ApplicationConfig {
private final UserRepository userRepository;
@Bean
public UserDetailsService userDetailsService() {
return username -> userRepository.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config)
throws Exception {
return config.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
🐸 Библиотека джависта
#DevLife
📌 6 принципов безопасности API
API — это не просто интерфейс, а ворота в вашу систему. Без должной защиты они становятся уязвимой точкой для атак.
🔐 Ключевые принципы безопасности API
— Использование HTTPS
— Аутентификация и авторизация
— Ограничение запросов
— Валидация входных данных
— Управление доступом на основе ролей (RBAC)
— Мониторинг и логирование
🔗 Подробнее в статье
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
🔧 Spring Boot Actuator: кастомные health indicators для мониторинга
В production приложениях часто недостаточно стандартных health checks от Spring Boot. Например, нужно проверить доступность внешнего API, очереди сообщений или специфичную бизнес-логику.
🔹 Решение
▪️ Создание custom health indicator
@Component
public class ExternalApiHealthIndicator implements HealthIndicator {
private final RestTemplate restTemplate;
private final String apiUrl;
@Override
public Health health() {
try {
ResponseEntity<String> response = restTemplate
.getForEntity(apiUrl + "/health", String.class);
if (response.getStatusCode().is2xxSuccessful()) {
return Health.up()
.withDetail("endpoint", apiUrl)
.withDetail("responseTime", "120ms")
.build();
}
return Health.down()
.withDetail("endpoint", apiUrl)
.withDetail("status", response.getStatusCode())
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.withException(e)
.build();
}
}
}
management:
endpoint:
health:
show-details: always
health:
defaults:
enabled: true
State Machine Pattern для AI-агентов
Джависты знают: сложная бизнес-логика требует управления состоянием. В мире LLM хаос LangChain сменился строгой структурой LangGraph. По сути, это реализация Finite State Machine, где переходы определяет нейросеть.
Зачем это в Enterprise:
— предсказуемость: вы жёстко задаёте граф переходов;
— persistence: состояние агента можно сохранить в БД (Postgres) и восстановить при падении;
— type safety: контроль структуры данных между шагами.
Курс по архитектуре агентов уже стартовал.
Записаться на курс
Сомневаетесь? Гляньте первую лекцию — там база про устройство современных агентов.
🎯 Перестань инжектить зависимости через @Autowired на полях
❌ Было:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private EmailService emailService;
@Autowired
private ValidationService validationService;
}
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
private final ValidationService validationService;
}
🐸 Библиотека джависта
#DevLife
🐳 Магия Docker CLI
Если ты перезапускаешь контейнер или лезешь внутрь через exec, чтобы посмотреть процессы. То эта команда для тебя. Она показывает все процессы за секунду → docker top.
🔹 Зачем это нужно
— Показывает запущенные процессы внутри контейнера без входа в него.
— Видно PID, пользователя, нагрузку на CPU и команду запуска.
— Полезно для мониторинга и быстрой диагностики проблем с производительностью.
🔹 Как использовать
— Базовый вывод: docker top container_id
— С кастомным форматом (как ps): docker top container_id aux
— Можно фильтровать по пользователю или искать конкретный процесс.
— Удобно в скриптах для автоматизации проверок.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
✔️ SQL-тест: Фильтрация активных рекламных кампаний
Задача из реального интервью в Google 👇
📦 Задание
Вы аналитик Google Ads. Нужно найти все объявления, которые:
— Имеют статус 'active'
— Показов больше 500,000
— Обновлены в 2024 году
Таблица google_ads на картинке. Напишите SQL-запрос для фильтрации.
Ставьте → 🔥, если нравится формат. Если нет → 🤔
💬 Решения под спойлер. Сравним, какое будет лучше.
🐸 Библиотека собеса по Java
#practise
🐸 Библиотека джависта
#DevLife
Мультиагентные системы: взгляд изнутри
В мире Java есть LangChain4j, но основные инновации обкатываются на Python. Курс «Разработка ИИ-агентов» — это отличный способ понять архитектурные паттерны построения LLM-приложений.
Что изучаем (на Python):
— жизненный цикл агента и ReAct;
— оркестрацию через графы (LangGraph);
— интеграцию с корпоративными данными (RAG).
Знание этих паттернов позволит вам эффективно проектировать AI-сервисы и на Java. Для курса нужен базовый Python.
Смотреть первую лекцию
Записаться
🖥 От REST к gRPC и GraphQL
В статье рассмотрены 3 подхода к построению API. Также автор показывает, как объединить gRPC и GraphQL, чтобы фронт получал гибкие запросы, а бэк получал скорость и эффективность.
🔗 Подробнее в статье
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
😮 Топ-вакансий для джавистов за неделю
Java-разработчик — от 250 000 ₽ — офис (Екатеринбург)
Java-developer Middle/Middle+ — удалёнка
Java разработчик (senior) — удалёнка
➡️ Еще больше топовых вакансий — в нашем канале Java jobs
🔥 Топ-10 интересных ошибок в реальных проектах
PVS-Studio собрали подборку самых интересных багов 2025 года из крупных Open Source проектов.
Тут есть всё: неочевидные языковые нюансы, которые ломают логику, ошибки из-за особенностей инициализации, проблемы с типами там, где их не ждёшь. Каждая ошибка разобрана с примерами кода и объяснением, почему она возникла.
Особенно понравится тем, кто любит копаться в деталях языка и понимать, как на самом деле работает JVM под капотом.
🔗 Читать на Habr
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Шаг 6: Auth Controller
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthenticationManager authenticationManager;
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@PostMapping("/login")
public ResponseEntity<AuthResponse> login(@RequestBody AuthRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.email(),
request.password()
)
);
UserDetails user = userDetailsService.loadUserByUsername(request.email());
String token = jwtService.generateToken(user);
return ResponseEntity.ok(new AuthResponse(token));
}
}
jwt:
secret: ${JWT_SECRET}
expiration: 86400000 # 24 hours
spring:
security:
filter:
dispatcher-types: REQUEST, ERROR, ASYNC
🔐 Spring Security 6 + JWT: Полная настройка за 10 минут
Настраиваем современную аутентификацию с JWT токенами в Spring Boot 3.x.
Шаг 1: Зависимости
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
</dependencies>
@ServiceЧитать полностью…
public class JwtService {
@Value("${jwt.secret}")
private String secretKey;
@Value("${jwt.expiration}")
private long jwtExpiration;
private Key getSigningKey() {
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
return Keys.hmacShaKeyFor(keyBytes);
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("authorities", userDetails.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.toList());
return Jwts.builder()
.claims(claims)
.subject(userDetails.getUsername())
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + jwtExpiration))
.signWith(getSigningKey())
.compact();
}
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parser()
.verifyWith((SecretKey) getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return username.equals(userDetails.getUsername())
&& !isTokenExpired(token);
}
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
private Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
}
🖥 На GitHub есть отличный репозиторий
useful-java-links — там собраны лучшие материалы по Java. В репозитории найдёте библиотеки, фреймворки, инструменты и образовательные материалы по разным направлениям
🔹 Отдельный акцент сделан на решениях для работы с СУБД, поисковиками, технологиями обработки больших данных и ML. Список регулярно пополняется новыми ссылками и остаётся актуальным.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Stateful Architecture: как это работает в AI
Java-разработчики знают цену управлению состоянием. В мире AI к этому пришли только сейчас с появлением LangGraph.
Вместо хаотичных скриптов теперь строят графы, где состояние передаётся явно, как контекст в Spring. Это позволяет создавать надёжных агентов с долгосрочной памятью и транзакционной логикой выполнения задач.
На курсе разбираем эти паттерны. Даже если пишете на Java, понимание архитектуры агентов — мастхэв для интеграции AI в энтерпрайз.
Записаться на курс
Смотрите вводный урок бесплатно (про архитектуру и графы).
🎧 Что послушать — #подкаст Javaswag #84
🔹 Ведущий: Дмитрий Волыхин
🔹 Гость: Иван Лягаев
🔹 Продолжительность: 1 час 50 минут
Иван рассказывает о Scala, её применении в банковской сфере, системе эффектов, платформенных задачах и кодогенерации. Также обсуждаются переходы между языками программирования, виртуальные потоки в Java, AI-ассистенты и работа с монорепозиториями.
🔹 Ключевые темы выпуска
04:36 — Парадигмы программирования
16:00 — Система эффектов в Scala
22:38 — Scala в банке
27:21 — Типичный Scala-сервис
33:17 — HTTP библиотеки
37:13 — Трассировка и мониторинг
44:37 — Контекст
49:30 — Переходы между языками программирования
51:54 — Type Class в Scala
57:13 — Java и Kotlin
01:00:38 — Проблемы, Сообщество и Scala
01:07:41 — Доклад о виртуальных потоках в Java
01:16:34 — ТехДолг
01:21:02 — Генерация клиентов и спецификаций API
01:29:16 — Кодогенерация
01:31:06 — Монорепозитории и многорепозитории
01:35:42 — Платформенные задачи
01:38:04 — AI-ассистенты
01:45:15 — Непопулярное мнение
🔗 Слушать выпуск
🐸 Библиотека джависта
#DevLife
🐸 Библиотека джависта
#DevLife
⚙️ Генерим Spring Boot-фичи с AI
Нужно быстро набросать сервис для бизнес-функции? AI поможет сэкономить часы на шаблонах, валидации и boilerplate.
📝 Промпт:
Generate a Spring Boot REST endpoint that handles [описание бизнес-логики]. Include request/response DTOs, validation, exception handling, and service-layer interaction. Use best practices and explain design decisions.
Use Java 17+ features if possible, чтобы сразу писать современноAdd unit tests for controller and service, чтобы не откладывать на потомMake it modular for future feature extension, если планируется масштабирование