- Published on
[ Spring ] 스프링 어노테이션, 객체 정리
- Authors
- Name
- 유사공대생
정리를 하게 된 계기
요즘 스프링을 공부할 때 잘 짜시는 분의 코드를 깃허브에서 긁어와서 분석하면서 적용하고 있다. 그래서 그런지 나도 모르는 어노테이션을 적용하는 경우가 많았다. 그래서 그분의 코드를 제 프로젝트에 적용하면서 어노테이션을 적용하는 이유를 정리해가면서 사용하려고 한다.
스프링의 어노테이션(annotation)이란?
어노테이션이란 자바 코드에 추가적인 정보를 제공하는 메타데이터(metadata)이다. 어노테이션을 사용하여 클래스, 메소드, 변수 등에 대한 정보를 표현하고, 이 정보를 프로그램에서 활용할 수 있다.
어노테이션은 @
기호로 시작하며, 컴파일러나 프레임워크 등에서 이 정보를 읽어 활용할 수 있다. 예를 들어, 스프링(Spring) 프레임워크에서는 @Controller
, @Service
, @Repository
등의 어노테이션을 사용하여 스프링이 해당 클래스를 어떻게 활용해야 하는지를 나타내며, 이 정보를 바탕으로 스프링 컨테이너가 빈(bean)을 생성하고 관리할 수 있다.
어노테이션은 사용자가 직접 정의할 수도 있으며, 이러한 사용자 정의 어노테이션을 사용하면 해당 어노테이션이 적용된 요소에 대한 추가적인 정보를 제공할 수 있다. 이를 통해 개발자는 코드를 더욱 명확하게 작성할 수 있고, 다른 개발자들이 코드를 이해하기 쉬워진다.
ResponseEntity 객체
스프링(Spring)에서는 ResponseEntity
를 사용하여 HTTP 응답(Response)을 생성할 수 있다. ResponseEntity
는 HTTP 응답 본문(body), 상태 코드(status code), 응답 헤더(response headers) 등을 포함할 수 있으며, 클라이언트에게 전송될 응답을 정의할 때 사용한다.
ResponseEntity
는 제네릭 클래스로, 응답 본문의 타입을 명시할 수 있다. 예를 들어, ResponseEntity<String>
은 String 타입의 응답 본문을 포함하는 HTTP 응답을 나타낸다.
ResponseEntity
의 주요 메소드는 다음과 같다.
getBody()
: 응답 본문을 반환한다.getStatusCode()
: 응답 상태 코드를 반환한다.getHeaders()
: 응답 헤더를 반환한다.
ResponseEntity
를 사용하면 HTTP 응답에 대한 세밀한 제어가 가능해지며, RESTful API를 개발할 때 유용하다. 예를 들어, 클라이언트에서 요청한 데이터가 없는 경우 404 Not Found 상태 코드와 함께 응답을 반환하거나, 클라이언트의 요청이 잘못된 경우 400 Bad Request 상태 코드와 함께 응답을 반환할 수 있다.
created()
네, ResponseEntity
에는 created
라는 정적 메소드가 있습니다. created
메소드는 HTTP 201 Created 상태 코드와 함께 리소스 생성 요청에 대한 응답을 생성할 때 사용됩니다.
created
메소드의 구문
public static <T> ResponseEntity<T> created(URI location)
T
: 응답 본문의 타입을 나타낸다.location
: 생성된 리소스의 위치를 나타내는 URI를 전달한다.
예를 들어, 다음 코드는 created
메소드를 사용하여 HTTP 201 Created 상태 코드와 함께 새로운 리소스를 생성하는 응답을 생성하는 방법을 보여준다.
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
// 새로운 유저를 생성하고, 생성된 유저를 location URI에 추가힌다.
User createdUser = userService.createUser(user);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(createdUser.getId())
.toUri();
// HTTP 201 Created 상태 코드와 생성된 유저를 반환한다.
return ResponseEntity.created(location).body(createdUser);
}
위 코드에서는 새로운 유저를 생성하고, 생성된 유저를 나타내는 URI를 location
변수에 저장한다. 그리고 created
메소드를 사용하여 HTTP 201 Created 상태 코드와 함께 해당 URI를 반환한다. 반환된 ResponseEntity
의 본문으로는 생성된 유저 객체가 포함된다.
ServletUriComponentsBuilder 클래스
ServletUriComponentsBuilder
는 Spring에서 제공하는 URI 빌더 클래스로, Servlet 기반의 애플리케이션에서 사용된다. ServletUriComponentsBuilder
를 사용하면 현재 요청(Request)에 대한 URI를 쉽게 생성할 수 있다.
ServletUriComponentsBuilder
의 fromCurrentRequest()
메소드는 현재 요청(Request)의 정보를 기반으로 URI를 생성한다. 예를 들어, 현재 요청의 URL과 파라미터 등의 정보를 이용하여 URI를 생성할 수 있다. 또한 path()
메소드를 사용하여 URI 경로를 추가하고, queryParam()
메소드를 사용하여 URI 쿼리 파라미터를 추가할 수 있다.
예를 들어, 다음 코드는 ServletUriComponentsBuilder
를 사용하여 현재 요청(Request)에 대한 URI를 생성하는 방법을 보여준다.
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
// 사용자 정보를 조회하고, 조회된 사용자 정보를 반환한다.
User user = userService.getUser(id);
return ResponseEntity.ok(user);
}
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
// 새로운 유저를 생성하고, 생성된 유저를 반환한다.
User createdUser = userService.createUser(user);
// 생성된 유저의 정보가 포함된 URI를 생성합니다.
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(createdUser.getId())
.toUri();
// HTTP 201 Created 상태 코드와 생성된 유저를 반환한다.
return ResponseEntity.created(location).body(createdUser);
}
위 코드에서는 ServletUriComponentsBuilder
를 사용하여 새로운 유저를 생성한 후, 생성된 유저를 반환할 때 생성된 유저의 정보가 포함된 URI를 생성한다. 생성된 URI는 created
메소드의 인자로 전달된다.
@Transactional
@Transactional
은 Java Spring에서 트랜잭션 처리를 위해 사용되는 애너테이션이다. 트랜잭션은 데이터베이스 상태를 변화시키는 일련의 작업을 하나의 논리적인 단위로 묶는 것을 의미한다. @Transactional
을 사용하는 이유는 다음과 같다.
원자성(Atomicity) 보장:
@Transactional
을 사용하면 트랜잭션 안에서 실행되는 모든 작업은 원자적으로 처리된다. 즉, 모든 작업이 성공적으로 완료되거나 전혀 수행되지 않는 것을 보장한다. 하나의 작업이 실패하면 이전 상태로 롤백된다.일관성(Consistency) 유지: 트랜잭션 내에서 실행되는 모든 작업은 데이터베이스의 일관성을 유지해야한다. 트랜잭션 시작 전과 종료 후의 데이터베이스 상태는 일관된 상태여야 한다.
@Transactional
은 트랜잭션 경계 내에서 일어나는 모든 변경을 커밋 또는 롤백함으로써 일관성을 보장한다.독립성(Isolation) 제공: 트랜잭션은 다른 트랜잭션과 독립적으로 실행됩니다. 각 트랜잭션은 격리 수준을 설정하여 서로의 작업에 영향을 주지 않는다.
@Transactional
은 트랜잭션의 격리 수준 설정을 지원하여 데이터베이스의 동시성 문제를 방지한다.지속성(Durability) 보장:
@Transactional
을 사용하면 트랜잭션이 성공적으로 완료되면 해당 작업은 영구적으로 데이터베이스에 반영된다. 이는 시스템 오류, 중단 또는 재시작과 같은 예기치 않은 상황에서도 데이터의 지속성을 보장한다.예외 처리:
@Transactional
은 트랜잭션 내에서 예외가 발생할 경우 롤백을 수행하여 데이터의 일관성을 유지한다. 예외가 발생하면 트랜잭션은 롤백되고 이전 상태로 복구된다.
즉, @Transactional
은 데이터베이스 작업을 트랜잭션 단위로 묶어서 일관성과 안전성을 보장하고 예외 처리를 간편하게 수행할 수 있도록 도와준다. 이를 통해 데이터베이스 조작에 대한 신뢰성과 안정성을 프로그램에서 유지할 수 있으며, 데이터의 일관성과 무결성을 유지할 수 있다. @Transactional
애너테이션을 사용하면 트랜잭션 관리를 자동화할 수 있고, 복잡한 트랜잭션 관련 로직을 개발자가 직접 구현할 필요가 없어진다. 이는 개발 생산성을 향상시키고 코드의 가독성을 높여준다.
Spring Framework에서 @Transactional
애너테이션은 메서드 레벨 또는 클래스 레벨에서 사용할 수 있다. 메서드에 @Transactional
을 추가하면 해당 메서드가 트랜잭션 내에서 실행되는 것으로 설정된다. 또한, @Transactional
을 클래스에 추가하면 클래스의 모든 public 메서드에 트랜잭션 설정이 적용된다.
- 예시
@Transactional
public void transferFunds(Account fromAccount, Account toAccount, BigDecimal amount) {
// 출금 계좌에서 잔액 차감
fromAccount.debit(amount);
// 입금 계좌에 잔액 추가
toAccount.credit(amount);
// 트랜잭션이 커밋되면 변경 사항이 데이터베이스에 반영됨
}
위의 코드에서 transferFunds
메서드에 @Transactional
애너테이션이 추가되었다. 이렇게 하면 메서드의 모든 작업은 하나의 트랜잭션으로 묶이게 된다. fromAccount.debit()
과 toAccount.credit()
메서드는 데이터베이스에서 변경이 이루어질 때까지 트랜잭션 내에서 실행된다. 그리고 트랜잭션이 커밋되면 변경 사항이 데이터베이스에 반영된다.
@Transactional
은 Spring의 트랜잭션 관리자에 의해 제어되며, 이를 통해 트랜잭션의 시작, 커밋, 롤백 등의 동작을 자동으로 처리한다. 이를 통해 데이터베이스 작업의 일관성과 안정성을 유지하고 예외 처리를 간소화할 수 있다.