모두가 사실 @Component의 특수 형태
주로 역할을 명확히 하고 부가적인 기능을 제공

일반 Bean 등록 → 스프링 컨테이너에 등록되어 재사용 가능한 컴포넌트 (Bean)
더 쉽게 말해 스프링 컨테이너가 관리하는 객체
@Component
public class EmailSender {
public void send(String email) { }
}주요 비즈니스 로직을 명시한 컴포넌트
@Service
public class UserService {
public User findById(Long id) { }
}주요 데이터 접근을 명시한 컴포넌트, DB의 예외가 Spring 예외로 변환됨
@Repository
public class UserRepository {
public User save(User user) { }
}요청을 분배, 처리하는 컨트롤러임을 명시한 컴포넌트
@Controller
public class UserController {
@GetMapping("/users")
public String list() { }
}RestController 와의 차이
Controller 는 일반적으로 View 를 반환함
데이터를 JSON 형태로 반환하기 위해서는 @ResponseBody 사용해야함
@Controller
@RequestMapping("/api/users")
public class UserApiController {
@GetMapping
@ResponseBody
public List<User> getUsers() {
return userService.findAll();
}
}하지만 RestController는 Controller + ResponseBody 의 형태
매번 데이터 반환이 필요할 때 ResponseBody를 사용하지 않아도 됨
💡
모두가 사실 @Component의 특수 형태
주로 역할을 명확히 하고 부가적인 기능을 제공
Spring 의 DI 에 따라, 스프링 컨테이너가 자동으로 Bean 주입하도록 요청하는 것
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}위 컴포넌트 부분에서의 UserRepository 의 객체를 이 서비스의 userRepository 에 주입함
개발자가 new 로 객체를 만드는 것이 아님
💡
다만 이러한 필드 주입은 더 이상 잘 사용되지 않는다
외부에서 접근이 불가하고 수정할 수 없다 → 테스트가 힘들다
생성자 주입에 대해서 많이 사용하고 있다
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired // 생성자 1개면 생략 가능
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}같은 타입의 Bean 이 여러 개 일때 이름으로 선택하도록 하는 것
// UserRepository 구현체가 2개
@Component("mySQLUserRepository")
public class MySQLUserRepository implements UserRepository { }
@Component("mongoUserRepository")
public class MongoUserRepository implements UserRepository { }
@Service
public class UserService {
@Autowired
@Qualifier("mySQLUserRepository") // 선택
private UserRepository userRepository;
}같은 타입의 Bean 이 여러 개 일때 우선적으로 선택하게 하는 것
@Component
@Primary // ← 우선 선택
public class MySQLUserRepository implements UserRepository { }
@Component
public class MongoUserRepository implements UserRepository { }
@Autowired // 우선 선택된 컴포넌트가 주입됨
private UserRepository userRepository; 💡
@Qualifier > @Primary > 이름 매칭 순 으로 우선순위를 가짐
url 경로로 선언된 HTTP 요청을 처리함
@RequestMapping(value = "/users", method = RequestMethod.GET)
public String getUsers() { }다만 이제는 요청 메서드를 직접 명시할 수 있어, 이 부분이 더 많이 쓰임
@GetMapping("/users") // = @RequestMapping(method = GET)
@PostMapping("/users") // = @RequestMapping(method = POST)
@PutMapping("/users") // = @RequestMapping(method = PUT)
@DeleteMapping("/users") // = @RequestMapping(method = DELETE)
@PatchMapping("/users") // = @RequestMapping(method = PATCH)url 경로에 선언된 부분을 파라미터로 바인딩 함
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { }쿼리 파라미터를 자동으로 파라미터로 바인딩함
// GET /search?keyword=spring&page=1
@GetMapping("/search")
public List<Product> search(@RequestParam String keyword,
@RequestParam int page) { }@RequestParam(required = false) // 필수 아님
@RequestParam(defaultValue = "1") // 기본값
@RequestParam("q") // 파라미터 이름 다를 때
String keyword요청의 바디에 JSON을 자동으로 객체 변환 (보통 DTO의 객체로 변환)
@PostMapping("/users")
public User createUser(@RequestBody UserRequest request) { }요청의 바디가 Form일 경우 (application/x-www-form-urlencoded)
자동으로 객체로 변환
@PostMapping("/users")
public String createUser(@ModelAttribute UserForm form) { }헤더의 값을 파라미터로 바인딩
@GetMapping("/users/me")
public User getMe(@RequestHeader("Authorization") String token) { }
요청:
GET /users/me
Authorization: test testing123
token 의 값은 "test testing123"쿠키의 값을 파라미터로 바인딩
@GetMapping("/users/me")
public User getMe(@CookieValue("SESSION") String sessionId) { }
요청:
GET /users/me
Cookie: SESSION=xyz789
↓
쿠키 추출:
sessionId = "xyz789"
sessionId 의 값은 xyz789반환 값을 View 가 아닌 HTTP 의 바디로 보내라는 의미
@Controller
public class UserController {
@GetMapping("/api/users")
@ResponseBody
public List<User> getUsers() {
return userService.findAll();
}
}
List<User> 데이터를 JSON으로 변환해서 Body에 담아 보냄!상태 코드를 설정함
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED) // 201
public User createUser(@RequestBody UserRequest request) {
return userService.create(request);
}