← Назад к вопросам

В чём разница между аннотациями @Component, @Repository, @Service и @Controller?

1.3 Junior🔥 211 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между @Component, @Repository, @Service и @Controller

Эти аннотации используются в Spring для маркировки классов и автоматической регистрации их в контексте приложения как бинов. Они помогают организовать код по слоям архитектуры и являются специализированными версиями базовой аннотации @Component.

@Component

@Component — это базовая аннотация для любого Spring-управляемого компонента. Это универсальное обозначение для класса, который должен быть создан и управляться Spring контейнером.

@Component
public class EmailService {
    public void sendEmail(String to, String message) {
        System.out.println("Sending email to " + to);
    }
}

@Component
public class NotificationService {
    private EmailService emailService;
    
    public NotificationService(EmailService emailService) {
        this.emailService = emailService;
    }
    
    public void notify(String message) {
        emailService.sendEmail("admin@example.com", message);
    }
}

Характеристики:

  • Самая общая аннотация
  • Используется для универсальных компонентов
  • Spring автоматически создаёт бин и внедряет зависимости
  • Обычно не имеет дополнительной семантики

@Service

@Service — специализированная версия @Component для сервисов бизнес-логики. Обозначает класс, который содержит бизнес-логику приложения.

@Service
public class UserService {
    private UserRepository userRepository;
    private PasswordEncoder passwordEncoder;
    
    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }
    
    // Бизнес-логика
    public User registerUser(String email, String password) {
        if (userRepository.findByEmail(email).isPresent()) {
            throw new UserAlreadyExistsException("User already registered");
        }
        
        User user = new User();
        user.setEmail(email);
        user.setPassword(passwordEncoder.encode(password));
        
        return userRepository.save(user);
    }
    
    public User getUserById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User not found"));
    }
    
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

Характеристики:

  • Обозначает сервис-слой
  • Содержит бизнес-логику
  • Используется для оркестрации операций
  • Может быть обёрнут прокси для AOP (транзакции, кэширование)
  • Spring автоматически управляет её жизненным циклом

@Repository

@Repository — специализированная версия @Component для доступа к данным. Обозначает класс, который работает с базой данных.

@Repository
public class UserRepositoryImpl implements UserRepository {
    private final JdbcTemplate jdbcTemplate;
    
    public UserRepositoryImpl(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    @Override
    public Optional<User> findById(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        try {
            User user = jdbcTemplate.queryForObject(sql, 
                new UserRowMapper(), id);
            return Optional.of(user);
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }
    
    @Override
    public Optional<User> findByEmail(String email) {
        String sql = "SELECT * FROM users WHERE email = ?";
        try {
            User user = jdbcTemplate.queryForObject(sql, 
                new UserRowMapper(), email);
            return Optional.of(user);
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }
    
    @Override
    public User save(User user) {
        String sql = "INSERT INTO users (email, password) VALUES (?, ?)";
        jdbcTemplate.update(sql, user.getEmail(), user.getPassword());
        return user;
    }
}

// С Spring Data JPA часто используется интерфейс
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
    List<User> findByAgeGreaterThan(int age);
}

Характеристики:

  • Обозначает слой доступа к данным
  • Работает с БД, API или другими источниками данных
  • Spring автоматически преобразует DataAccessException в специфичные исключения
  • Помогает отделить логику доступа к данным
  • С JPA часто используется как интерфейс

@Controller

@Controller — специализированная версия @Component для веб-контроллеров. Обозначает класс, который обрабатывает HTTP запросы.

@Controller
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    // Обработка GET запросов
    @GetMapping("/{id}")
    @ResponseBody
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }
    
    // Обработка POST запросов
    @PostMapping
    @ResponseBody
    public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {
        User user = userService.registerUser(request.getEmail(), request.getPassword());
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }
    
    // Обработка DELETE запросов
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

// Или с @RestController (комбинирует @Controller + @ResponseBody)
@RestController
@RequestMapping("/api/users")
public class UserRestController {
    private final UserService userService;
    
    public UserRestController(UserService userService) {
        this.userService = userService;
    }
    
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

Характеристики:

  • Обозначает веб-контроллер
  • Обрабатывает HTTP запросы
  • Маршрутизирует запросы к сервисам
  • Возвращает ответы (представления или данные)
  • @RestController — это комбинация @Controller + @ResponseBody

Сравнительная таблица

Аспект@Component@Service@Repository@Controller
НазначениеУниверсальный бинБизнес-логикаДоступ к даннымHTTP обработка
Слой архитектурыЛюбойApplicationInfrastructurePresentation
ПереиспользуемостьДаДаНетНет
AOP помощьНетДа (транзакции)Да (исключения)Нет
Обработка исключенийНетНетДа (преобразует)Да (HTTP статусы)

Архитектурная слоистость

HTTP Запрос
    ↓
[Presentation Layer]
@Controller - обрабатывает HTTP, валидирует input
    ↓
[Application Layer]
@Service - оркестрирует логику, управляет транзакциями
    ↓
[Infrastructure Layer]
@Repository - доступ к БД
    ↓
[Domain Layer]
@Component - доменные объекты, утилиты

Пример полной архитектуры

// Controller слой (Presentation)
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    private final OrderService orderService;
    
    @PostMapping
    public ResponseEntity<OrderResponse> createOrder(@RequestBody CreateOrderRequest request) {
        Order order = orderService.createOrder(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(new OrderResponse(order));
    }
}

// Service слой (Application)
@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final PaymentService paymentService;
    
    @Transactional
    public Order createOrder(CreateOrderRequest request) {
        Order order = new Order();
        order.setCustomer(request.getCustomer());
        order.setItems(request.getItems());
        
        // Бизнес-логика: проверка инвентаря, расчёт стоимости и т.д.
        
        Order savedOrder = orderRepository.save(order);
        paymentService.processPayment(savedOrder);
        return savedOrder;
    }
}

// Repository слой (Infrastructure)
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    List<Order> findByCustomerId(Long customerId);
}

// Component слой (Domain/Utils)
@Component
public class OrderCalculator {
    public BigDecimal calculateTotal(List<OrderItem> items) {
        return items.stream()
            .map(item -> item.getPrice().multiply(new BigDecimal(item.getQuantity())))
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}

Правила использования

  1. @Controller — используй для веб-контроллеров, которые обрабатывают HTTP
  2. @Service — используй для бизнес-логики и оркестрации операций
  3. @Repository — используй для доступа к данным
  4. @Component — используй для остального (утилиты, конвертеры, слушатели)

Правильное использование этих аннотаций делает архитектуру более понятной, упрощает тестирование и облегчает поддержку кода.