포스트

2023-03-27-TIL

2023-03-27-TIL

Today I Learned

Spring Data R2DBC와 여러 Spring Data 모듈

한 애플리케이션에 Spring Data 모듈이 둘 이상 들어오면(예: R2DBC와 Redis, JPA와 MongoDB) 리포지토리 인터페이스를 어느 모듈이 구현할지 정해야 한다. Spring Data 문서에 따르면 클래스패스에서 리포지토리 팩토리가 여러 개 발견되면 strict repository configuration 모드로 들어가고, 다음 기준으로 모듈을 고른다.

  • 리포지토리가 모듈 전용 인터페이스(R2dbcRepository, JpaRepository 등)를 상속하면 그 모듈의 후보가 된다.
  • 도메인 클래스에 모듈 전용 애너테이션(JPA의 @Entity, MongoDB의 @Document 등)이 붙어 있으면 그 모듈의 후보가 된다.
  • 둘 다 애매하면 @EnableR2dbcRepositories(basePackages = ...)처럼 모듈별로 스캔할 패키지를 나누어 구분한다.

CrudRepository처럼 범용 인터페이스만 상속하고 도메인 클래스에도 표시가 없으면 어느 모듈에도 바인딩되지 않으므로, 다중 모듈 환경에서는 모듈 전용 인터페이스를 쓰거나 패키지를 분리하는 편이 안전하다.


Java Agent

Java Agent란 JVM에서 동작하는 애플리케이션으로 JVM의 다양한 이벤트를 전달받거나 정보 쿼리, 바이트 코드 제어 등을 특정 API를 통해 수행할 수 있다.

  • Agent는 지정된 JVM의 실행 가능한 최초 진입점인 main 메서드를 가로채기 할 수 있다.
  • 지정된 JVM에서 실행된다.
  • 지정된 JVM의 동일한 System Class Loader 내에서 로드된다.
  • 지정된 JVM의 Security Policy 및 Context의 영향을 받는다.
  • 실행 시간에 동적으로 bytecode를 조작할 수 있다.

이 동작은 java.lang.instrument 패키지에 정의되어 있다. 에이전트를 시작하는 방법은 두 가지가 대표적이다.

  • 명령행 옵션 -javaagent:<jarpath>[=<options>]로 시작한다. JAR의 매니페스트에 Premain-Class를 적고, 그 클래스의 premain(String agentArgs, Instrumentation inst)이 애플리케이션의 main보다 먼저 호출된다. premain이 반환해야 애플리케이션이 시작된다.
  • 이미 실행 중인 JVM에 붙는 방식에서는 Agent-Class와 agentmain 메서드를 사용한다.

premain이 받는 Instrumentation 객체로 ClassFileTransformer를 등록하면 클래스가 로드될 때 바이트코드를 바꿀 수 있다. APM 도구나 코드 커버리지 도구가 애플리케이션 코드 수정 없이 계측을 넣을 수 있는 이유가 이것이다.


Spring Boot에서 HTTP 상태 코드 지정하기

REST API는 처리 결과를 본문뿐 아니라 상태 코드로도 알려야 한다. 생성은 201 Created, 본문 없는 성공은 204 No Content, 잘못된 요청은 400, 대상 없음은 404처럼 HTTP 메서드와 결과에 맞는 코드를 고르는 것이 먼저다. Spring MVC에서 상태 코드를 정하는 방법은 크게 세 가지다.

  • ResponseEntity: 상태 코드, 헤더, 본문을 함께 담아 반환한다. Spring 문서는 이를 상태와 헤더를 가진 @ResponseBody라고 설명한다. 분기마다 다른 코드를 돌려줘야 할 때 가장 유연하다.
  • @ResponseStatus: 컨트롤러 메서드나 예외 클래스에 붙여 고정된 상태 코드를 지정한다.
  • ResponseStatusException: 서비스나 컨트롤러에서 상태 코드와 사유를 담은 예외를 던진다. 예외 클래스를 따로 만들지 않아도 된다.
1
2
3
4
5
@PostMapping("/members")
public ResponseEntity<MemberResponse> create(@RequestBody MemberRequest request) {
    MemberResponse saved = memberService.create(request);
    return ResponseEntity.created(URI.create("/members/" + saved.id())).body(saved);
}
  • https://restfulapi.net/http-methods/
  • https://www.amitph.com/spring-return-specific-http-status/
  • https://stackabuse.com/how-to-return-http-status-codes-in-a-spring-boot-application/
  • https://stackoverflow.com/questions/24292373/spring-boot-rest-controller-how-to-return-different-http-status-codes
  • https://www.baeldung.com/spring-mvc-controller-custom-http-status-code
  • ResponseEntity (Spring Framework Reference)
이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다