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

В чем разница между аннотациями component, repository и service в Spring?

1.8 Middle🔥 161 комментариев
#Spring Boot и Spring Data#Spring Framework

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

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

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

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

Все три аннотации — это specialization общего механизма Spring для управления бинами (beans), но каждая используется в определённом слое архитектуры с различными целями.

@Component

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

@Component
public class NotificationSender {
    public void send(String message) {
        System.out.println("Sending: " + message);
    }
}

// Можно внедрить в другой класс
@Component
public class EmailService {
    @Autowired
    private NotificationSender sender;
}

@Service

Это специализация @Component для классов, содержащих бизнес-логику (use cases, orchestration). Семантически указывает, что класс представляет бизнес-сервис.

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private EmailService emailService;
    
    // Бизнес-логика
    @Transactional
    public void registerUser(UserRegistrationRequest request) {
        User user = new User();
        user.setEmail(request.getEmail());
        user.setName(request.getName());
        
        userRepository.save(user);
        emailService.sendWelcomeEmail(user.getEmail());
    }
    
    public List<User> getAllActiveUsers() {
        return userRepository.findByStatus("ACTIVE");
    }
}

@Repository

Это специализация @Component для классов, взаимодействующих с БД (Data Access Layer). Также имеет специальный функционал — Spring автоматически транслирует исключения БД в Spring DataAccessException.

@Repository
public class UserRepository {
    @PersistenceContext
    private EntityManager em;
    
    public User findById(Long id) {
        return em.find(User.class, id);
    }
    
    public void save(User user) {
        em.persist(user);
    }
    
    // Exception translation: SQL exceptions -> DataAccessException
    public List<User> findByEmail(String email) {
        try {
            return em.createQuery(
                "SELECT u FROM User u WHERE u.email = :email",
                User.class
            ).setParameter("email", email)
             .getResultList();
        } catch (SQLException e) {
            // Spring преобразует в DataAccessException
            throw new DataAccessException("Database error", e);
        }
    }
}

Таблица различий

Аспект@Component@Service@Repository
ПредназначениеЛюбой управляемый компонентБизнес-логика и use casesРабота с БД
Слой архитектурыAnyApplication/DomainInfrastructure
Exception translationНетНетДа (DataAccessException)
СемантикаGenericBusiness operationsData access
Пример использованияUtility, converter, validatorService, facade, orchestratorDAO, persistence

Иерархия наследования

    @Component (базовая аннотация)
         ↑
      / | \
     /  |  \
 @Service @Repository @Controller
          (другие специализации)

Все три создают управляемые бины, но с различной семантикой и функциональностью.

Правильное применение в примере

// Слой доступа к данным
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByStatus(String status);
}

// Слой бизнес-логики
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private EmailValidator emailValidator;  // Обычный @Component
    
    @Transactional
    public void createUser(UserRequest request) {
        if (!emailValidator.isValid(request.getEmail())) {
            throw new InvalidEmailException();
        }
        User user = User.fromRequest(request);
        userRepository.save(user);
    }
}

// Валидатор как utility-компонент
@Component
public class EmailValidator {
    public boolean isValid(String email) {
        return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
    }
}

Ключевое отличие: Exception Translation

Только @Repository предоставляет автоматическое преобразование исключений:

// В @Repository методе
public User findUser(Long id) throws SQLException {
    // SQLException автоматически преобразуется в DataAccessException
    return getUserFromDatabase(id);
}

// В @Service можно ловить специфичные исключения
@Service
public class UserService {
    @Autowired
    private UserRepository repo;
    
    public User getUser(Long id) {
        try {
            return repo.findUser(id);
        } catch (DataAccessException e) {
            log.error("Database error", e);
            throw new UserNotFoundException();
        }
    }
}

Лучшие практики

  • Используй @Service для бизнес-логики и оркестрации
  • Используй @Repository для всех классов работы с БД
  • Используй @Component только для вспомогательных компонентов
  • Выбор аннотации должен отражать архитектурный слой класса
  • Spring Data repositories автоматически помечаются как @Repository