В чем разница между аннотациями component, repository и service в Spring?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между @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 | Работа с БД |
| Слой архитектуры | Any | Application/Domain | Infrastructure |
| Exception translation | Нет | Нет | Да (DataAccessException) |
| Семантика | Generic | Business operations | Data access |
| Пример использования | Utility, converter, validator | Service, facade, orchestrator | DAO, 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