В чём разница между аннотациями @Component, @Repository, @Service и @Controller?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между @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 обработка |
| Слой архитектуры | Любой | Application | Infrastructure | Presentation |
| Переиспользуемость | Да | Да | Нет | Нет |
| 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);
}
}
Правила использования
- @Controller — используй для веб-контроллеров, которые обрабатывают HTTP
- @Service — используй для бизнес-логики и оркестрации операций
- @Repository — используй для доступа к данным
- @Component — используй для остального (утилиты, конвертеры, слушатели)
Правильное использование этих аннотаций делает архитектуру более понятной, упрощает тестирование и облегчает поддержку кода.