
- Главная
- Каталог
- Интернет технологии
- Библиотека Java разработчика
Статистика канала
http://localhost:8081 в коде - самоубийство.
Eureka Server - это реестр.
OrderService) запускается, он звонит в Eureka: "Привет, я OrderService, мой IP такой-то".
UserService хочет найти заказы, он спрашивает Eureka: "Где сейчас живет OrderService?".
В коде:
Вам нужно просто добавить аннотацию @EnableDiscoveryClient, и магия произойдет сама. Сервисы будут находить друг друга по имени, а не по IP.
2️⃣ OpenFeign: Магия общения
Окей, адрес мы нашли. Теперь нужно отправить запрос.
Раньше мы использовали RestTemplate - это было громоздко и некрасиво.
Feign позволяет вызывать удаленный REST-сервис так, будто это обычный метод интерфейса в вашем коде.
Было (RestTemplate):
String url = "http://order-service/orders/" + userId;
List<Order> orders = restTemplate.getForObject(url, List.class); // Фу, нетипизированно
{}
Стало (FeignClient):
Вы просто пишете интерфейс, а реализацию Spring сгенерирует сам!
@FeignClient(name = "order-service") // Имя сервиса в Eureka
public interface OrderClient {
@GetMapping("/orders/{userId}")
List<Order> getUserOrders(@PathVariable Long userId);
}
// Использование в сервисе:
// List<Order> orders = orderClient.getUserOrders(123L);
{}
Это называется Декларативный REST-клиент. Чисто, красиво, типизировано.
3️⃣ API Gateway: Единая точка входа
Представьте, что у вас 50 микросервисов. Фронтенд не должен знать адреса каждого из них (api.com:8081, api.com:8082...). Это небезопасно и сложно (CORS error, привет 👋).
Spring Cloud Gateway - это вахтер на входе.
Весь внешний мир стучится только в него (например, на порт 8080), а он уже сам разруливает, куда отправить запрос.
Что он делает:
1. Маршрутизация: /users/** -> лети в UserService, /orders/** -> лети в OrderService.
2. Безопасность: Проверяет JWT токен один раз на входе.
3. Rate Limiting: "Не больше 10 запросов в секунду от этого юзера".
Пример конфига (application.yaml):
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE # lb = Load Balancer (через Eureka)
predicates:
- Path=/users/**
{}
⚡ Итог: Как это работает вместе?
1. Сервисы просыпаются и регистрируются в Eureka.
2. Фронтенд шлет запрос на Gateway.
3. Gateway спрашивает у Eureka адрес нужного сервиса и пересылает запрос.
4. Если сервисам нужно пообщаться между собой, они используют Feign.
#Java #Microservices #SpringCloud #Eureka #Feign
📲 Мы в MAX
👉@BookJava.war файл, закинуть его в папку... 🤯
Spring Boot принес концепцию Fat JAR (Жирный JAR).
🍔 1. Fat JAR - "Всё своё ношу с собой"
Spring Boot упаковывает ваше приложение, все библиотеки (зависимости) и даже сам веб-сервер (Tomcat) в один единственный файл .jar.
Этот файл работает как .exe в Windows. Ему ничего не нужно, кроме установленной Java.
Как собрать?
В терминале (в папке проекта):
# Для Maven
./mvnw clean package
# Для Gradle
./gradlew build
{}
В папке target (или build/libs) появится файл myapp-0.0.1-SNAPSHOT.jar.
Как запустить?
Где угодно (на сервере, на ноутбуке друга), где есть Java:
java -jar myapp.0.0.1-SNAPSHOT.jar
{}
Всё! Сервер стартует.
🐳 2. Docker - "Работает везде"
JAR это хорошо. Но что, если на сервере стоит Java 11, а у вас Java 17? Или другая ОС? Начинается проблема "На моем компьютере работало!".
Docker решает это, упаковывая ваше приложение вместе с Java и операционной системой в Контейнер.
Пишем Dockerfile
Создайте файл без расширения с именем Dockerfile в корне проекта.
Вариант для новичков (Простой):
# 1. Берем базовый образ с Java 17 (легковесный Alpine Linux)
FROM eclipse-temurin:17-jre-alpine
# 2. Копируем наш JAR внутрь образа
# (Предварительно нужно сделать mvn package руками!)
COPY target/*.jar app.jar
# 3. Говорим, какую команду запустить при старте контейнера
ENTRYPOINT ["java", "-jar", "/app.jar"]
{}
Как запустить:
# 1. Собираем образ (Image)
docker build -t my-spring-app .
# 2. Запускаем контейнер
# -p 8080:8080 пробрасывает порт наружу
docker run -p 8080:8080 my-spring-app
{}
🏗 3. Multi-stage Build (Уровень Pro)
В варианте выше вам нужно сначала собрать JAR руками. Это неудобно для CI/CD.
В профессиональном Dockerfile мы делаем сборку внутри Docker.
# --- Этап 1: Сборка (Build) ---
FROM maven:3.8.5-openjdk-17 AS builder
WORKDIR /app
COPY . .
# Собираем JAR, пропуская тесты (для скорости)
RUN mvn clean package -DskipTests
# --- Этап 2: Запуск (Run) ---
# Берем чистый, маленький образ для запуска
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# Копируем ТОЛЬКО готовый jar из первого этапа
COPY --from=builder /app/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
{}
Почему это круто? В финальном образе нет исходного кода и тяжелого Maven. Только Java и ваш JAR. Образ весит минимум, а собрать его можно одной командой docker build, даже если на компьютере вообще не установлена Java!
🔥 Итог
1. Maven/Gradle собирают код в один Fat JAR.
2. Dockerfile описывает среду для запуска.
3. Multi-stage build позволяет собирать и запускать приложение в изолированной среде, не засоряя систему.
#SpringBoot #Docker #DevOps #Deployment #Java
📲 Мы в MAX
👉@BookJavaUserService, вам не нужно, чтобы он реально лез в базу данных. Вам нужно проверить: "Если репозиторий вернет null, выбросит ли сервис ошибку?"
Для этого мы используем Mockito - библиотеку, которая создает "фейковые" объекты (моки).
Ключевые аннотации:
@ExtendWith(MockitoExtension.class) - включаем Mockito.
@Mock - "Создай фейковый объект" (например, UserRepository).
@InjectMocks - "Создай тестируемый объект (UserService) и вставь в него моки".
💻 Пример Unit-теста:
@ExtendWith(MockitoExtension.class) // 1. Включаем Mockito
class UserServiceTest {
@Mock
private UserRepository userRepository; // Фейк
@InjectMocks
private UserService userService; // Реальный сервис с фейком внутри
@Test
void shouldReturnUser_WhenExists() {
// GIVEN (Дано) - Настраиваем поведение мока
User mockUser = new User("Alex");
// "Если кто-то вызовет findById(1), верни mockUser"
Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));
// WHEN (Когда) - Вызываем метод сервиса
User result = userService.findById(1L);
// THEN (Тогда) - Проверяем результат
Assertions.assertEquals("Alex", result.getName());
// Проверяем, что метод репозитория действительно вызывался 1 раз
Mockito.verify(userRepository, times(1)).findById(1L);
}
}
{}
🐢 2. Integration-тесты: Тяжелая артиллерия
Иногда нужно проверить, правильно ли мапится JSON в контроллере или работает ли SQL-запрос. Тут нам нужен Spring Context.
Ключевые аннотации:
@SpringBootTest - Поднимает весь контекст приложения (тяжело и медленно, но честно).
@WebMvcTest - Поднимает только веб-слой (Контроллеры). Сервисы и БД не грузятся.
@MockBean - Главная магия Spring Test. Это как @Mock, только этот мок кладется прямо в Spring Context, заменяя собой настоящий бин.
💻 Пример теста Контроллера (@WebMvcTest):
@WebMvcTest(UserController.class) // Грузим только контроллер
class UserControllerTest {
@Autowired
private MockMvc mockMvc; // Инструмент для имитации HTTP-запросов
@MockBean // Заменяем настоящий сервис заглушкой в контексте Spring
private UserService userService;
@Test
void shouldReturnStatus200() throws Exception {
Mockito.when(userService.findById(1L)).thenReturn(new User("Alex"));
mockMvc.perform(get("/users/1")) // Делаем GET запрос
.andExpect(status().isOk()) // Ждем 200 OK
.andExpect(jsonPath("$.name").value("Alex")); // Проверяем JSON
}
}
{}
⚔️ @Mock vs @MockBean - Не путать!
Это самый частый вопрос.
1. @Mock (из org.mockito): Используется в Unit-тестах. Быстро. Spring про него ничего не знает.
2. @MockBean (из spring-boot-test): Используется в Integration-тестах. Spring находит этот бин в контексте и подменяет его на мок. Медленнее.
🔥 Итог
Mockito.when(...).
MockMvc.
Как сделать так, чтобы ваши интеграции на Camel не стали узким местом при росте нагрузки?Что будет на вебинаре:
application.properties. Это старый формат (ключ=значение).
Весь мир переходит на YAML (.yaml или .yml). Он читабельнее и поддерживает иерархию.
Было (.properties):
spring.datasource.url=jdbc:postgresql://localhost/db
spring.datasource.username=admin
server.port=8080
{}
Стало (.yaml):
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost/db
username: admin
{}
Меньше дублирования, глазам приятнее.
2️⃣ Как достать настройки в коде?
Способ А: Простой (@Value)
Подходит для точечных настроек.
@Value("${server.port}")
private int port;
{}
Способ Б: Профессиональный (@ConfigurationProperties)
Если настроек много (например, настройки почты или API), лучше собрать их в отдельный класс. Это дает типизацию и проверку данных!
@ConfigurationProperties(prefix = "mail")
public record MailConfig(String host, int port, String username) {}
{}
Теперь вы просто внедряете MailConfig в свои сервисы, как обычный бин.
3️⃣ Профили (Profiles) - Киллер-фича
На локальной машине у вас H2 база данных, а на продакшене - PostgreSQL. Как не менять конфиги вручную?
Используйте Профили.
Вы создаете несколько файлов рядом с основным application.yaml:
application-dev.yaml (для разработки)
application-prod.yaml (для боевого сервера)
В основном файле вы указываете, какой профиль активен по умолчанию:
spring:
profiles:
active: dev # По умолчанию грузим dev-настройки
{}
А при запуске на сервере вы просто передаете флаг, и Spring подхватит нужный файл, перетерев дефолтные настройки:
java -jar app.jar -Dspring.profiles.active=prod
4️⃣ Секреты (Никаких паролей в Git!)
Самая страшная ошибка - закоммитить application-prod.yaml с паролем от боевой БД в репозиторий. ☠️
Правило: В файлах храним только дефолтные/безопасные значения. Реальные пароли передаем через Переменные Окружения (Environment Variables).
Spring Boot имеет строгий приоритет загрузки. Переменные окружения OS имеют более высокий приоритет, чем файлы.
spring.datasource.password=secret
SPRING_DATASOURCE_PASSWORD=SuperSecurePass123
Spring увидит переменную в системе и проигнорирует то, что написано в файле. Ваш секрет в безопасности.
🔥 Итог
1. Используйте YAML вместо properties.
2. Группируйте настройки через @ConfigurationProperties.
3. Разделяйте среды через Профили (dev, test, prod).
4. Никогда не храните боевые пароли в файлах. Используйте ENV vars.
#SpringBoot #Configuration #YAML #DevOps #BestPractices
📲 Мы в MAX
👉@BookJava{"status": 404, "message": "User not found"}.
Раньше, чтобы добиться хорошего сценария, приходилось писать try-catch в каждом методе контроллера. Это ужасно.
В Spring Boot есть элегантное решение - @ControllerAdvice.
🛡 Что это такое?
Это перехватчик (Interceptor), который работает по принципу Аспектно-Ориентированного Программирования (AOP). Он "сидит" над всеми вашими контроллерами и ловит исключения, которые вылетели из них, прежде чем они дойдут до пользователя.
🛠 Как настроить? (3 шага)
1. Создаем DTO для ошибки
Нам нужен красивый формат ответа, чтобы фронтенд всегда знал, чего ожидать.
public record ErrorResponse(int statusCode, String message, LocalDateTime timestamp) {}
{}
2. Создаем Глобальный Обработчик
Используем аннотацию @RestControllerAdvice. Это тот же @ControllerAdvice, но он автоматически добавляет @ResponseBody ко всем ответам (мы же пишем REST API).
Внутри класса мы пишем методы-обработчики с аннотацией @ExceptionHandler.
@RestControllerAdvice
public class GlobalExceptionHandler {
// 1. Ловим конкретную ошибку (например, сущность не найдена)
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(404, ex.getMessage(), LocalDateTime.now()));
}
// 2. Ловим ошибки валидации (если передали кривой JSON)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
String errors = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.joining(", "));
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(400, errors, LocalDateTime.now()));
}
// 3. Ловим всё остальное (Fallback)
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(500, "Произошла внутренняя ошибка", LocalDateTime.now()));
}
}
{}
3. Бросаем исключения в Сервисе
Теперь в коде сервиса можно не бояться и просто бросать ошибки. Обработчик их поймает.
public User getUser(Long id) {
return repo.findById(id)
.orElseThrow(() -> new EntityNotFoundException("User with id " + id + " not found"));
}
{}
⚡ Почему это круто?
1. Чистота кода: В контроллерах нет try-catch блоков. Только "счастливый путь" (happy path).
2. Единообразие: Весь API возвращает ошибки в одинаковом формате.
3. Безопасность: Вы контролируете, какой текст ошибки увидит пользователь, и скрываете системные детали.
🔥 Итог
try-catch в контроллерах.
@RestControllerAdvice.
EntityNotFoundException) на HTTP-статусы (404 Not Found).
#SpringBoot #Java #ExceptionHandling #BestPractices
📲 Мы в MAX
👉@BookJava@Entity)
Сначала мы объясняем Java, как выглядит наша таблица. Обычный класс превращается в таблицу с помощью пары аннотаций.
@Entity // Это таблица в БД
@Table(name = "users")
public class User {
@Id // Это Primary Key
@GeneratedValue(strategy = GenerationType.IDENTITY) // Авто-инкремент
private Long id;
private String email;
private int age;
private boolean active;
// Геттеры, сеттеры...
}
{}
🪄 2. Репозиторий (Магия)
Вместо написания класса UserDao, мы просто создаем интерфейс.
public interface UserRepository extends JpaRepository<User, Long> {
// Здесь пусто! Но методы уже есть.
}
{}
Наследуясь от JpaRepository, вы сразу получаете готовые методы:
.save(user) - сохранить/обновить.
.findById(id) - найти по ID (возвращает Optional).
.findAll() - найти всех.
.deleteById(id) - удалить.
Ни одной строчки SQL писать не пришлось! 😎
🔮 3. Derived Queries (Запросы из имени)
Что, если нужно найти пользователя по email? Или всех активных пользователей старше 18 лет?
Вы просто пишете метод в интерфейсе с правильным названием, и Spring сам составляет SQL-запрос.
public interface UserRepository extends JpaRepository<User, Long> {
// SQL: SELECT * FROM users WHERE email = ?
Optional<User> findByEmail(String email);
// SQL: SELECT * FROM users WHERE active = true AND age > ?
List<User> findByActiveTrueAndAgeGreaterThan(int age);
// SQL: EXISTS (SELECT 1 FROM users WHERE email = ?)
boolean existsByEmail(String email);
}
{}
Синтаксис простой: find + By + ИмяПоля + Условие (если нужно).
🛠 4. Если магия не справилась (@Query)
Иногда названия методов становятся слишком длинными и уродливыми (findByNameAndAgeAndActiveAnd...). Или нужен сложный JOIN.
Тогда мы берем управление в свои руки и пишем запрос на JPQL (Java Persistence Query Language) - это SQL, но оперирующий классами, а не таблицами.
@Query("SELECT u FROM User u WHERE u.email LIKE %:domain%")
List<User> findUsersByEmailDomain(@Param("domain") String domain);
{}
⚡ Транзакции (@Transactional)
База данных требует транзакций (всё или ничего).
В Spring Boot методы репозитория уже транзакционны (только на чтение).
Если же вы в сервисе делаете несколько операций подряд (снять деньги, перевести деньги), вешайте @Transactional над методом сервиса.
@Service
public class PaymentService {
@Transactional // Если упадет ошибка, все изменения откатятся
public void transferMoney() {
repo.withdraw(...);
repo.deposit(...);
}
}
{}
🔥 Итог
Spring Data JPA убирает 90% рутинной работы с БД.
1. Создали @Entity.
2. Создали интерфейс extends JpaRepository.
3. Нужен поиск? Написали метод findByField.
4. Сложный запрос? Написали @Query.
#SpringBoot #JPA #Hibernate #Database #SQL
📲 Мы в MAX
👉@BookJavapom.xml, пишете main метод, и у вас волшебным образом поднимается Tomcat, настраивается JSON-конвертер и подключается логирование?
За этим стоят два кита Spring Boot: Starters и AutoConfiguration.
1️⃣ Starters (Стартеры) - "Всё включено"
В старом Spring, чтобы сделать веб-приложение, нужно было вручную найти версии для Spring MVC, Tomcat, Jackson, Validation API... и молиться, чтобы они были совместимы.
Starter — это готовый набор зависимостей (dependencies), собранный в один пакет. Это как "Комбо-обед" в ресторане.
spring-boot-starter-web.
* Внутри: Tomcat + Spring MVC + Jackson + Logback.
spring-boot-starter-test.
*Внутри: JUnit + Mockito + AssertJ + Hamcrest.
Вам больше не нужно думать о версиях библиотек. Spring Boot следит за "BOM" (Bill of Materials) и гарантирует, что все версии внутри стартера дружат друг с другом.
2️⃣ AutoConfiguration - "Умный детектив"
Это мозг фреймворка. Когда приложение запускается, Spring Boot начинает сканировать ваш classpath (все подключенные библиотеки jar).
Он рассуждает примерно так:
1. "Так, я вижу, что в зависимостях есть класс H2Driver?" "Значит, программист хочет базу данных. Создам-ка я ему бин DataSource с настройками для H2!"
2. "Я вижу классы Tomcat и Spring MVC?" "Значит, нужно поднять встроенный веб-сервер на порту 8080 и настроить DispatcherServlet."
3. "О, программист сам создал свой бин DataSource?" "Окей, тогда я отступаю и свою автоконфигурацию не применяю."
Вся эта логика держится на аннотациях @Conditional...:
@ConditionalOnClass: Создать бин, если найден класс X.
@ConditionalOnMissingBean: Создать бин, ТОЛЬКО если программист не создал такой же сам.
⚙️ Главная кнопка: @SpringBootApplication
Вы вешаете эту аннотацию над main классом. На самом деле это "матрешка", внутри которой спрятаны 3 другие аннотации:
@SpringBootConfiguration // Говорит: "Это конфигурационный класс"
@EnableAutoConfiguration // Говорит: "ВКЛЮЧИ МАГИЮ!" (запусти сканирование classpath)
@ComponentScan // Говорит: "Ищи пользовательские бины в этом пакете"
public @interface SpringBootApplication { ... }
{}
🕵️♂️ Pro-Tip: Как увидеть магию?
Иногда автоконфигурация мешает, или вы не понимаете, почему Spring решил подключить ту или иную базу.
Добавьте в application.properties одну строчку:
debug=true
{}
При запуске в консоль вывалится Condition Evaluation Report. Там будет честно написано:
Отзывы канала
всего 15 отзывов
- Добавлен: Сначала новые
- Добавлен: Сначала старые
- Оценка: По убыванию
- Оценка: По возрастанию
Каталог Телеграм-каналов для нативных размещений
Библиотека Java разработчика — это Telegam канал в категории «Интернет технологии», который предлагает эффективные форматы для размещения рекламных постов в Телеграмме. Количество подписчиков канала в 10.5K и качественный контент помогают брендам привлекать внимание аудитории и увеличивать охват. Рейтинг канала составляет 8.4, количество отзывов – 15, со средней оценкой 4.9.
Вы можете запустить рекламную кампанию через сервис Telega.in, выбрав удобный формат размещения. Платформа обеспечивает прозрачные условия сотрудничества и предоставляет детальную аналитику. Стоимость размещения составляет 6993.0 ₽, а за 85 выполненных заявок канал зарекомендовал себя как надежный партнер для рекламы в TG. Размещайте интеграции уже сегодня и привлекайте новых клиентов вместе с Telega.in!
Вы снова сможете добавить каналы в корзину из каталога
Комментарий