Spring Framework는 객체를 관리하고 계층 간 의존성을 자동 주입하기 위해 다양한 어노테이션을 제공한다.
이 중 실제 개발 현장에서 자주 사용되는 핵심 어노테이션들을 중심으로 설명한다.
1. @Component, @Service, @Repository, @Controller
이 네 가지는 Spring Bean 등록용 어노테이션이다.
즉, Spring이 해당 클래스를 컨테이너에서 관리하도록 등록하는 역할을 한다.
내부적으로는 모두 @Component를 기반으로 하며, 역할에 따라 의미만 다르다.
(1) @Component
가장 기본적인 Bean 등록용 어노테이션이다.
Helper, Util, Validator 등 특정 계층에 속하지 않는 일반 클래스를 Bean으로 등록할 때 사용한다.
import org.springframework.stereotype.Component;
@Component
public class FileNameHelper {
public String makeFileName(String original) {
return System.currentTimeMillis() + "_" + original;
}
}
이후 다른 클래스에서 자동 주입하여 사용할 수 있다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class FileService {
private final FileNameHelper fileNameHelper;
@Autowired
public FileService(FileNameHelper fileNameHelper) {
this.fileNameHelper = fileNameHelper;
}
public void saveFile(String fileName) {
String newName = fileNameHelper.makeFileName(fileName);
System.out.println("저장 파일명: " + newName);
}
}
(2) @Service
비즈니스 로직을 담당하는 계층에 사용한다.
트랜잭션이 걸리거나 여러 DAO를 조합하는 등의 처리를 담당한다.
코드상 기능은 @Component와 동일하지만, 역할을 명확히 구분하기 위해 사용한다.
import org.springframework.stereotype.Service;
@Service
public class MemberService {
public String getMemberGrade(int point) {
if (point > 1000) return "VIP";
if (point > 500) return "GOLD";
return "SILVER";
}
}
(3) @Repository
데이터베이스와 직접 통신하는 DAO 계층에 사용한다.
@Repository는 예외 변환 기능이 내장되어 있어, JDBC나 MyBatis, JPA에서 발생한 예외를
Spring 공통 예외(DataAccessException)로 변환해준다.
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.Map;
@Repository
public class MemberRepository {
private static final Map<Integer, String> MEMBER_DB = new HashMap<>();
static {
MEMBER_DB.put(1, "홍길동");
MEMBER_DB.put(2, "이몽룡");
}
public String findMemberName(int id) {
return MEMBER_DB.get(id);
}
}
(4) @Controller / @RestController
Controller 계층은 클라이언트의 요청을 받아 처리하는 역할을 한다.
@Controller는 View(JSP, Thymeleaf 등) 를 반환하고,
@RestController는 JSON 데이터를 직접 반환한다.
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MemberViewController {
@GetMapping("/member/view")
public String showMember(Model model) {
model.addAttribute("name", "홍길동");
return "memberView"; // memberView.jsp
}
}
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
@RestController
public class MemberApiController {
@GetMapping("/api/member")
public Member getMember() {
return new Member("홍길동", "VIP");
}
}
public class Member {
private String name;
private String grade;
public Member(String name, String grade) {
this.name = name;
this.grade = grade;
}
// getter, setter 생략
}
2. @Autowired와 의존성 주입(Dependency Injection)
@Autowired는 Bean을 자동 주입해주는 어노테이션이다.
즉, @Component, @Service, @Repository, @Controller로 등록된 Bean을
필요한 곳에 가져다 쓸 수 있게 해준다.
필드 주입 (비권장)
@Autowired
private MemberService memberService;
간단하지만 테스트나 유지보수 시 불편하므로 권장되지 않는다.
생성자 주입 (권장)
@Service
public class OrderService {
private final MemberService memberService;
@Autowired
public OrderService(MemberService memberService) {
this.memberService = memberService;
}
}
Spring 4.3 이상부터는 생성자가 하나뿐이면 @Autowired를 생략할 수 있다.
Lombok과 함께 사용 (@RequiredArgsConstructor)
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class OrderService {
private final MemberService memberService;
public void process() {
System.out.println(memberService.getMemberGrade(700));
}
}
3. @Value (프로퍼티 값 주입)
Spring의 설정 파일(application.properties 또는 .yml)에 정의된 값을 클래스에 주입할 수 있다.
# application.properties
app.title=FOO PORTAL
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AppInfo {
@Value("${app.title}")
private String title;
public void printTitle() {
System.out.println("애플리케이션 이름: " + title);
}
}
4. @RequestMapping 계열 (요청 매핑)
Spring MVC에서 요청 URL을 메서드에 연결할 때 사용한다.
HTTP Method별로 축약형 어노테이션이 존재한다.
예시 1. @RequestMapping
@Controller
@RequestMapping("/member")
public class MemberController {
@RequestMapping("/list")
public String listMembers() {
return "memberList";
}
}
예시 2. HTTP 메서드별 축약형
@RestController
@RequestMapping("/api/member")
public class MemberRestController {
@GetMapping("/{id}")
public String getMember(@PathVariable int id) {
return "회원번호: " + id;
}
@PostMapping
public String addMember(@RequestParam String name) {
return "등록된 회원: " + name;
}
}
5. @Transactional
DB 변경이 포함된 비즈니스 로직에 트랜잭션을 적용한다.
메서드 내 예외 발생 시 자동으로 롤백이 수행된다.
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class PaymentService {
@Transactional
public void pay(Long memberId, int amount) {
// 1. 잔액 차감
// 2. 결제 내역 기록
// 예외 발생 시 모든 작업이 롤백됨
System.out.println("회원 " + memberId + "에게 " + amount + "원 결제 처리 완료");
}
}
마무리
Spring에서 자주 사용하는 어노테이션은 단순히 “문법”이 아니라,
프로젝트 구조를 명확히 하고 계층 간 책임을 분리하기 위한 약속이다.
- @Component : 범용 Bean 등록
- @Service : 비즈니스 로직
- @Repository : 데이터 접근
- @Controller / @RestController : 요청 처리
- @Autowired, @Value : 의존성 및 설정값 주입
- @Transactional : 트랜잭션 처리
각 어노테이션은 “Spring이 언제, 어떻게 객체를 관리할지” 결정하는 핵심 도구이며,
이 개념만 정확히 이해해도 대부분의 Spring 프로젝트 구조를 파악할 수 있다.
'Java > Spring' 카테고리의 다른 글
| [Spring] Filter와 Interceptor의 차이 정리 (0) | 2025.10.31 |
|---|---|
| [Spring] Spring Framework vs Spring Boot 비교 정리 (0) | 2025.10.29 |
| [Spring] 순서 의존 AOP로 인해 파라미터 순서만 바꿔도 코드가 동작하지 않은 이유 (0) | 2025.10.21 |