Микросервисы на Java: дорожная карта для новичка

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Микросервисы на Java: не бойтесь, это проще, чем кажется

Вы когда-нибудь смотрели на монолитное приложение и думали: «Вот бы разделить это на части, чтобы не бояться, что одно изменение сломает всё»? Поздравляю — вы созрели для микросервисов. В мире Java эта тема обросла мифами о невероятной сложности и куче технологий. На самом деле, стартовать можно с двух классов и одного файла application.yml.

В этой статье мы не будем строить космический корабль. Мы напишем два простых микросервиса, которые поговорят друг с другом по HTTP, и разберёмся, с чего реально начать. Никакой магии — только Java, Spring Boot и здравый смысл.

Что такое микросервис (на пальцах)

Представьте себе ресторан. Монолит — это когда один повар делает всё: и суп варит, и стейк жарит, и посуду моет. Микросервисы — это команда: один повар отвечает только за супы, второй — за мясо, третий — за десерты. Каждый работает независимо, но вместе создают общее меню.

В Java микросервис — это самостоятельное приложение, которое отвечает за одну бизнес-функцию (например, «Управление пользователями» или «Обработка заказов»). У него своя база данных, свой код, и он общается с другими сервисами через сеть (обычно по HTTP/REST или через брокеры сообщений).

С чего начать: инструментарий джентльмена

Для первого проекта вам понадобится всего три вещи:

  • Java 17+ — современная версия с полезными фичами (records, sealed classes).
  • Spring Boot 3.x — самый популярный фреймворк для микросервисов на Java. Он берёт на себя 80% рутины.
  • Maven или Gradle — для сборки. Maven проще для старта, Gradle быстрее.

Дополнительно, когда захотите усложнить:

  • Docker — чтобы упаковать сервис в контейнер.
  • Spring Cloud — для обнаружения сервисов (Service Discovery) и балансировки.
  • PostgreSQL/H2 — база данных на выбор.

Совет: не пытайтесь сразу выучить Kubernetes и Kafka. Начните с простого REST-общения.

Пишем первый микросервис: Сервис пользователей

Создадим простой микросервис, который умеет отдавать информацию о пользователях. Используем Spring Initializr (start.spring.io) или создадим проект вручную.

Добавьте зависимости в pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Теперь напишем модель пользователя:

import jakarta.persistence.*;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    // конструкторы, геттеры, сеттеры (можно использовать Lombok)
    public User() {}

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // геттеры и сеттеры
}

Репозиторий (упрощённый доступ к данным):

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

И контроллер — REST-ручка:

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserRepository userRepository;

    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
}

Готово! Это уже микросервис. Запустите main метод, и он будет слушать порт 8080. Проверьте: GET localhost:8080/api/users — получите пустой список.

Пишем второй микросервис: Сервис заказов

Создайте новый проект (или модуль) с теми же зависимостями. Теперь он будет обращаться к первому сервису, чтобы получить данные о пользователе.

Создадим простой REST-клиент с помощью RestClient (новый в Spring 6):

import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;

@Service
public class UserServiceClient {

    private final RestClient restClient;

    public UserServiceClient() {
        this.restClient = RestClient.create("http://localhost:8080");
    }

    public String getUserNameById(Long userId) {
        return restClient.get()
                .uri("/api/users/{id}", userId)
                .retrieve()
                .body(User.class)
                .getName();
    }
}

Обратите внимание: мы жёстко закодировали адрес первого сервиса. В реальности так не делают — используют Service Discovery (Eureka или Consul). Но для старта сойдёт.

Теперь контроллер заказов:

@RestController
@RequestMapping("/api/orders")
public class OrderController {

    private final UserServiceClient userServiceClient;

    public OrderController(UserServiceClient userServiceClient) {
        this.userServiceClient = userServiceClient;
    }

    @GetMapping("/{userId}/name")
    public String getOrderUserName(@PathVariable Long userId) {
        return "Заказ для пользователя: " + userServiceClient.getUserNameById(userId);
    }
}

Запустите оба сервиса. Первый на порту 8080, второй — на 8081 (добавьте в application.properties: server.port=8081). Теперь при запросе GET localhost:8081/api/orders/1/name второй сервис сходит в первый и вернёт имя пользователя.

Как сделать общение надёжнее

В примере выше, если первый сервис упадёт, второй просто выбросит ошибку. В реальном мире это недопустимо. Вот что добавляют в боевых проектах:

  • Circuit Breaker (Resilience4j) — если сервис не отвечает, не ждать вечно, а быстро вернуть запасной ответ.
  • Retry — попробовать ещё раз через секунду.
  • Service Discovery (Eureka) — чтобы не хардкодить адреса, а получать их из реестра.

Пример добавления Circuit Breaker:

import io.github.resilience4j.circuitbreaker.annotation.Circuit                

Блоги

Рекомендаций по книгам