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

Для чего нужна аннотация Service в Spring?

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

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

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

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

# Аннотация @Service в Spring Framework

@Service — это специализированная аннотация Spring, которая используется для маркирования класса как сервиса (Service Layer). Она является подтипом аннотации @Component и призвана повысить читаемость и организацию кода.

Что такое @Service

1. Основное назначение

@Service — это аннотация-маркер, которая сообщает Spring, что класс является сервисом бизнес-логики приложения. Spring автоматически создаёт bean этого класса и управляет его жизненным циклом.

import org.springframework.stereotype.Service;

@Service
public class UserService {
    // Это автоматически создаст bean типа UserService
    // и поместит его в Spring Application Context
}

Иерархия аннотаций

@Component (базовая аннотация)
    |
    +-- @Service (для Service Layer)
    +-- @Repository (для Data Access Layer)
    +-- @Controller (для Presentation Layer)
    +-- @RestController (для REST Presentation Layer)

2. Управление жизненным циклом bean'а

Spring автоматически управляет созданием, инициализацией и удалением bean'а:

@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @PostConstruct
    public void init() {
        System.out.println("OrderService инициализирован");
    }
    
    public Order createOrder(OrderRequest request) {
        return orderRepository.save(new Order(request));
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("OrderService удаляется");
    }
}

3. Внедрение зависимостей (Dependency Injection)

@Service позволяет Spring автоматически внедрять зависимости через @Autowired:

@Service
public class PaymentService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private NotificationService notificationService;
    
    @Autowired
    private PaymentGateway paymentGateway;
    
    public void processPayment(Long orderId) {
        Order order = orderRepository.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
        
        // Используем внедрённые зависимости
        paymentGateway.charge(order.getTotal());
        notificationService.sendConfirmation(order);
    }
}

4. Управление транзакциями

@Service часто используется с @Transactional для управления транзакциями БД:

@Service
@Transactional
public class TransferService {
    
    @Autowired
    private AccountRepository accountRepository;
    
    // Все методы этого сервиса будут выполняться в транзакции
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        Account from = accountRepository.findById(fromId).orElseThrow();
        Account to = accountRepository.findById(toId).orElseThrow();
        
        from.debit(amount);
        to.credit(amount);
        
        // Если произойдёт исключение, обе операции откатятся
    }
    
    @Transactional(readOnly = true)
    public BigDecimal getBalance(Long accountId) {
        return accountRepository.findById(accountId)
            .map(Account::getBalance)
            .orElse(BigDecimal.ZERO);
    }
}

5. Область действия (Scope) bean'а

По умолчанию @Service создаёт Singleton bean, но можно изменить область действия:

// Singleton (по умолчанию) — одна копия на всё приложение
@Service
public class UserService {
}

// Prototype — новая копия при каждом внедрении
@Service
@Scope("prototype")
public class PrototypeService {
}

// Request scope — новая копия для каждого HTTP запроса
@Service
@Scope("request")
public class RequestScopedService {
}

// Session scope — новая копия для каждой сессии пользователя
@Service
@Scope("session")
public class SessionScopedService {
}

6. Реальный пример: многоуровневая архитектура

// Repository Layer
@Repository
public class UserRepository extends JpaRepository<User, Long> {
}

// Service Layer
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(UserRequest request) {
        // Валидация
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new UserAlreadyExistsException(request.getEmail());
        }
        
        // Бизнес-логика
        User user = new User();
        user.setEmail(request.getEmail());
        user.setPassword(encodePassword(request.getPassword()));
        
        return userRepository.save(user);
    }
    
    public Optional<User> getUser(Long id) {
        return userRepository.findById(id);
    }
}

// Controller Layer
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody UserRequest request) {
        User user = userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(user);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return userService.getUser(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
}

7. Service с несколькими репозиториями

@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private ItemRepository itemRepository;
    
    @Autowired
    private CustomerRepository customerRepository;
    
    @Transactional
    public Order createOrder(Long customerId, List<OrderItem> items) {
        // Проверяем существование клиента
        Customer customer = customerRepository.findById(customerId)
            .orElseThrow(() -> new CustomerNotFoundException(customerId));
        
        // Создаём заказ
        Order order = new Order();
        order.setCustomer(customer);
        order.setStatus(OrderStatus.PENDING);
        
        // Сохраняем товары
        for (OrderItem item : items) {
            item.setOrder(order);
            itemRepository.save(item);
        }
        
        // Сохраняем заказ
        return orderRepository.save(order);
    }
}

8. Тестирование Service

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserService userService;
    
    @Test
    void testCreateUserSuccess() {
        // Arrange
        UserRequest request = new UserRequest("test@example.com", "password");
        User expectedUser = new User("test@example.com", "hashedPassword");
        
        when(userRepository.existsByEmail("test@example.com")).thenReturn(false);
        when(userRepository.save(any(User.class))).thenReturn(expectedUser);
        
        // Act
        User result = userService.createUser(request);
        
        // Assert
        assertNotNull(result);
        assertEquals("test@example.com", result.getEmail());
        verify(userRepository).save(any(User.class));
    }
    
    @Test
    void testCreateUserAlreadyExists() {
        UserRequest request = new UserRequest("existing@example.com", "password");
        
        when(userRepository.existsByEmail("existing@example.com")).thenReturn(true);
        
        assertThrows(UserAlreadyExistsException.class, 
            () -> userService.createUser(request));
    }
}

Преимущества использования @Service

  1. Читаемость кода — сразу видно, что класс отвечает за бизнес-логику
  2. Организация архитектуры — четкое разделение слоев приложения
  3. Управление жизненным циклом — Spring автоматически создаёт и удаляет bean'ы
  4. Dependency Injection — простое внедрение зависимостей
  5. Транзакционность — легко добавить @Transactional
  6. Тестируемость — легко мокировать зависимости
  7. Масштабируемость — легко добавлять новые сервисы

Резюме

@Service используется для:

  • Маркирования класса как сервиса бизнес-логики
  • Автоматического создания Spring bean'а
  • Управления жизненным циклом объекта
  • Внедрения зависимостей
  • Организации кода в многоуровневую архитектуру
  • Упрощения управления транзакциями и логирования
Для чего нужна аннотация Service в Spring? | PrepBro