@Service

Spring에서 비즈니스 로직을 처리하는 서비스 계층 빈을 등록하는 어노테이션입니다. Controller와 Repository 사이에서 핵심 로직을 담당합니다.

기본 사용법

@Service
public class UserService {

    private final UserRepository userRepository;

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

    public User findById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
    }

    @Transactional
    public User createUser(UserDto dto) {
        // 비즈니스 로직
        validateDuplicate(dto.getEmail());
        User user = new User(dto.getName(), dto.getEmail());
        return userRepository.save(user);
    }
}

계층 구조에서의 위치

@Controller  ─ 요청/응답 처리
    ↓
@Service     ─ 비즈니스 로직 ← 여기
    ↓
@Repository  ─ DB 접근

@Service vs @Component

// 동작은 동일
@Component
public class UserService { }

@Service
public class UserService { }
항목@Component@Service
기능빈 등록빈 등록
추가 기능없음없음
차이점범용서비스 계층 명시

왜 구분해서 쓰나?

// X 역할을 알 수 없음
@Component
public class UserService { }

@Component
public class UserRepository { }

// O 역할이 명확함
@Service
public class UserService { }

@Repository
public class UserRepository { }

트랜잭션 처리

@Service
public class OrderService {

    @Transactional
    public void createOrder(OrderDto dto) {
        // 재고 차감
        productService.decreaseStock(dto.getProductId());

        // 주문 생성
        Order order = new Order(dto);
        orderRepository.save(order);

        // 결제 처리
        paymentService.pay(dto.getPaymentInfo());

        // 하나라도 실패하면 전체 롤백
    }
}

실무 패턴

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)  // 기본 읽기 전용
public class UserService {

    private final UserRepository userRepository;

    public User findById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
    }

    @Transactional  // 쓰기 작업만 트랜잭션 적용
    public User create(UserDto dto) {
        return userRepository.save(new User(dto));
    }
}

CSLOG에서 보기