@Service

코딩냥이·2024년 9월 10일

Annotation

목록 보기
5/34

@Service

@Service는 스프링 프레임워크에서 비즈니스 로직을 처리하는 클래스를 표시하는 어노테이션입니다.

기능

  • 클래스를 스프링의 서비스 계층 컴포넌트로 지정합니다.
  • @Component의 특화된 형태로, 비즈니스 로직을 포함하는 클래스임을 명시적으로 나타냅니다.
  • 스프링의 컴포넌트 스캔 메커니즘에 의해 자동으로 감지되고 빈으로 등록됩니다.

사용 방법

@Service
public class UserService {

    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User createUser(User user) {
        // 사용자 생성 로직
        return userRepository.save(user);
    }

    public User getUserById(Long id) {
        // 사용자 조회 로직
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));
    }

    // 기타 비즈니스 메서드...
}

주요 특징

  1. 비즈니스 로직 캡슐화: 애플리케이션의 핵심 비즈니스 로직을 포함합니다.
  2. 트랜잭션 관리: 주로 @Transactional 어노테이션과 함께 사용되어 트랜잭션을 관리합니다.
  3. 계층 구조: 일반적으로 프레젠테이션 계층(@Controller)과 데이터 액세스 계층(@Repository) 사이에 위치합니다.
  4. 의존성 주입: 다른 서비스나 리포지토리에 대한 의존성을 주입받아 사용합니다.

@Service vs @Component

@Service@Component의 특화된 형태입니다. 기능적으로는 동일하지만, 의미론적인 차이가 있습니다:

  • @Component: 일반적인 스프링 관리 컴포넌트
  • @Service: 비즈니스 로직을 처리하는 서비스 계층 컴포넌트
@Component
public class GenericComponent {
    // 일반적인 컴포넌트
}

@Service
public class BusinessService {
    // 비즈니스 로직을 처리하는 서비스
}

생명주기 관리

스프링 컨테이너는 @Service 어노테이션이 붙은 클래스의 인스턴스를 생성하고 관리합니다:

  1. 빈 생성: 애플리케이션 시작 시 스프링이 @Service 클래스의 인스턴스를 생성합니다.
  2. 의존성 주입: 필요한 의존성을 자동으로 주입합니다.
  3. 초기화: @PostConstruct 메서드가 있다면 호출합니다.
  4. 사용: 애플리케이션에서 서비스를 사용합니다.
  5. 소멸: 애플리케이션 종료 시 @PreDestroy 메서드가 있다면 호출합니다.

트랜잭션 관리

@Service 클래스는 주로 트랜잭션 관리와 함께 사용됩니다:

@Service
public class TransferService {

    @Autowired
    private AccountRepository accountRepository;

    @Transactional
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        Account fromAccount = accountRepository.findById(fromId)
            .orElseThrow(() -> new AccountNotFoundException("Account not found: " + fromId));
        Account toAccount = accountRepository.findById(toId)
            .orElseThrow(() -> new AccountNotFoundException("Account not found: " + toId));

        fromAccount.withdraw(amount);
        toAccount.deposit(amount);

        accountRepository.save(fromAccount);
        accountRepository.save(toAccount);
    }
}

테스트

@Service 클래스는 단위 테스트와 통합 테스트의 주요 대상이 됩니다:

@SpringBootTest
class UserServiceTest {

    @Autowired
    private UserService userService;

    @MockBean
    private UserRepository userRepository;

    @Test
    void createUser_ShouldReturnCreatedUser() {
        User user = new User("John Doe", "john@example.com");
        when(userRepository.save(any(User.class))).thenReturn(user);

        User createdUser = userService.createUser(user);

        assertNotNull(createdUser);
        assertEquals("John Doe", createdUser.getName());
        assertEquals("john@example.com", createdUser.getEmail());
        verify(userRepository).save(user);
    }
}

베스트 프랙티스

  1. 단일 책임 원칙: 각 서비스 클래스는 명확하고 구체적인 비즈니스 기능을 담당해야 합니다.
  2. 계층 분리: 서비스 계층은 프레젠테이션 계층과 데이터 액세스 계층을 분리하는 역할을 합니다.
  3. 느슨한 결합: 인터페이스를 사용하여 서비스를 정의하고 구현하면 느슨한 결합을 달성할 수 있습니다.
  4. 명확한 네이밍: 서비스 클래스의 이름은 그 역할을 명확히 나타내야 합니다 (예: UserService, OrderProcessingService).
  5. 예외 처리: 비즈니스 로직 관련 예외를 적절히 처리하고 필요시 커스텀 예외를 정의합니다.

결론

@Service 어노테이션은 스프링 애플리케이션의 비즈니스 로직을 구조화하고 관리하는 데 중요한 역할을 합니다. 이를 통해 관심사를 분리하고, 코드의 재사용성과 유지보수성을 향상시킬 수 있습니다. 서비스 계층은 애플리케이션의 핵심 기능을 담당하므로, 잘 설계된 서비스 클래스는 전체 애플리케이션의 품질과 성능에 큰 영향을 미칩니다.

profile
HelloMeow~!

0개의 댓글