포스트

2021-06-03-TIL

2021-06-03-TIL

@RequiredArgsConstructor

  • https://webdevtechblog.com/requiredargsconstructor-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-dependency-injection-4f1b0ac33561

Lombok의 @RequiredArgsConstructor는 초기화되지 않은 final 필드와, 선언 시점에 초기화되지 않은 @NonNull 필드마다 파라미터를 하나씩 받는 생성자를 만든다(Lombok 문서).

1
2
3
4
5
6
@Service
@RequiredArgsConstructor
public class RoomService {
    private final RoomRepository roomRepository;
    private final ReservationRepository reservationRepository;
}

빈에 생성자가 하나뿐이면 그 생성자에 @Autowired를 붙이지 않아도 된다(Spring 문서). Spring 팀도 생성자 주입을 권장한다. 객체를 불변으로 만들 수 있고, 필수 의존성이 null이 아님을 보장하며, 항상 완전히 초기화된 상태로 객체가 넘어가기 때문이다(Spring 문서). 같은 문서는 생성자 인자가 지나치게 많으면 클래스의 책임이 너무 많다는 신호라고도 적는다. Lombok이 생성자를 대신 써 주면 이 신호가 눈에 덜 띄므로, 필드 수가 늘어날 때는 한 번 의식해서 볼 필요가 있다.


Spring Boot + MyBatis 에서 쿼리 로깅

  • https://smallgiant.tistory.com/59
  • http://jmlim.github.io/spring/2018/12/26/spring-boot-logback-sql-pretty/
  • https://lee-mandu.tistory.com/352?category=715433
  • https://congsong.tistory.com/23

MyBatis는 매퍼 네임스페이스(매퍼 인터페이스의 패키지와 이름)를 로거 이름으로 쓴다. MyBatis 로깅 문서에 따르면 SQL 문은 DEBUG 레벨, 결과 행은 TRACE 레벨로 찍힌다. 그래서 Spring Boot에서는 매퍼 패키지의 로그 레벨만 올리면 된다.

1
logging.level.com.example.room.mapper=DEBUG

결과가 큰 쿼리에서는 TRACE를 켜면 로그가 넘치므로 SQL만 보고 싶을 때는 DEBUG에서 멈춘다. 값이 채워진 SQL을 보기 좋게 정렬해서 보고 싶다면 log4jdbc 같은 JDBC 프록시 드라이버를 쓰는 방법도 있다.


스프링에서 HTTP에 대한 테스트 코드를 작성하기

  • https://itmore.tistory.com/entry/MockMvc-%EC%83%81%EC%84%B8%EC%84%A4%EB%AA%85

MockMvc는 서버를 띄우지 않고 Spring MVC를 테스트하는 도구다. 실제 DispatcherServlet을 호출하되 서블릿 API는 spring-test의 목(mock) 구현을 쓴다(Spring 문서). 컨트롤러를 직접 생성해서 메서드를 부르는 단위 테스트는 요청 매핑, 데이터 바인딩, 메시지 변환, 검증, @ExceptionHandler를 확인할 수 없는데, MockMvc는 이것까지 함께 검증한다.

1
2
3
mockMvc.perform(get("/rooms").param("location", "서울"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$[0].location").value("서울"));

Spring Boot and OAuth2

  • https://daddyprogrammer.org/post/1754/spring-boot-oauth2-resourceserver/

OAuth 2.0에서 리소스 서버는 Bearer 토큰으로 보호되는 API를 가진 쪽이다. 인증과 권한 관리는 인가 서버에 맡기고, 리소스 서버는 요청에 담긴 토큰만 검증한다. Spring Security는 두 가지 토큰 형식을 지원한다. 서명된 JWT는 리소스 서버가 스스로 검증할 수 있고, 불투명(opaque) 토큰은 인가 서버에 물어봐야 검증할 수 있다(Spring Security 문서). 토큰이 없는 요청에는 WWW-Authenticate: Bearer 헤더로 응답한다.


JPA Transactional and Proxy

  • https://cobbybb.tistory.com/17
  • https://mommoo.tistory.com/92
  • https://www.baeldung.com/spring-jpa-soft-delete

@Transactional은 Spring이 빈을 프록시로 감싸고, 프록시가 메서드 호출 앞뒤에서 트랜잭션을 시작하고 끝내는 방식으로 동작한다. 그래서 프록시를 거치지 않는 호출에는 적용되지 않는다. Spring 문서는 같은 객체 안의 메서드가 다른 @Transactional 메서드를 부르는 자기 호출(self-invocation)은 실제 트랜잭션으로 이어지지 않는다고 명시한다.

1
2
3
4
5
6
public void register(Room room) {
    save(room); // this.save()라서 프록시를 거치지 않는다
}

@Transactional
public void save(Room room) { ... }

해결 방법은 트랜잭션이 필요한 메서드를 다른 빈으로 옮기거나, 바깥 메서드에 @Transactional을 거는 것이다. 문서는 자기 호출까지 트랜잭션으로 감싸야 한다면 프록시 대신 바이트코드를 직접 엮는 AspectJ 모드를 쓰라고 안내한다.

마지막 링크는 soft delete를 다룬다. 행을 실제로 지우지 않고 deleted 같은 플래그만 바꾸는 방식이다. Hibernate에서는 @SQLDelete로 삭제 SQL을 UPDATE로 바꾸고(Hibernate Javadoc), @Where로 조회할 때마다 지워지지 않은 행만 고르는 조건을 붙인다(Hibernate Javadoc).

참고한 자료외부 출처 6

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다