본문 바로가기

Programming/Java & JSP & Spring

(75)
[Spring] Guava RateLimiter 사용법 (spring throttling) Spring에서 throttling을 하기 위해 Guava의 RateLimiter가 주로 사용된다. 사용법과 예제를 정리해본다. Guava Rate Limiter Rate Limiter는 초당 실행횟수를 제어해서 throttling을 도와주는 클래스이다. 라이브러리 추가 dependencies { implementation("com.google.guava:guava:31.1-jre") } 1초에 한번 실행 describe("1초에 1번 실행") { val rateLimiter = RateLimiter.create(1.0) // RateLimiter 생성 repeat(10) { val startTime = ZonedDateTime.now().second rateLimiter.acquire() // = ra..
[Spring] 외부 API 호출 서비스 테스트코드 작성하기 (WebClient & MockWebServer) Spring에서는 API를 호출할 수 있는 많은 REST Client를 제공한다. 그 중에서도 WebClient가 가장 많이 추천되는 편이다. Spring 팀에서도 RestTemplate의 대안으로 WebClient를 추천하고 있고, Reactive 환경과 MSA를 생각하고 있다면, WebClient는 좋은 대안이 될 것이다. 그럼 이러한 WebClient로 작성한 서비스는 어떻게 테스트 코드를 작성할 수 있을까? 두가지 방법이 존재한다. Mockito를 사용하는 방법 실제 WebClient를 사용하고, MockWebServer를 호출하는 방법 Mockito를 이용해 일일히 stubbing하는 방법도 있지만, 이 방법은 너무 번거롭고 복잡하다. 또한, 테스트하려는 서비스가 WebClient 동작방식에 대..
[Spring boot] Hikari CP 적용 & 커넥션 누수 이슈 데이터베이스와 애플리케이션을 연결해주는 커넥션 풀은 다양한 오픈소스 라이브러리가 존재한다. Apache Commons DBCP Tomcat JDBC Bone CP Hikari CP 등등.. Spring boot 2.0부터는 Hikari CP를 default 커넥션 풀로 채택하고 있다. 따라서, 최근 프로젝트를 생성한 경우라면, 기본적으로 Hikari CP를 사용하기 때문에 굳이 다른 커넥션 풀로 전환하는 일은 드물 것이다. # Hikari CP 적용 Spring Boot가 기본적으로 데이터베이스에 대한 설정을 자동으로 생성해주기 때문에, 해당 설정을 특별히 제외하지 않았고, Spring Boot 2.0 이상의 프로젝트를 생성했다면 property 설정만으로 간단하게 Hikari CP를 구성할 수 있다. ..
[Spring] REQUIRES_NEW과 Exception (REQUIRES_NEW는 정말 독립적인가?) 흔히들 많이 사용하고 기본적으로 작동하는 것이 Propagation.REQUIRED 전파 레벨을 사용한다. 그 다음은 여러 이유로 REQUIRES_NEW 전파 레벨이 사용되는 편인데, 이 둘의 개념을 먼저 간단히 살펴보자. Propagation.REQUIRED 트랜잭션이 존재하면 기존의 트랜잭션이 전파된다. 만약 존재하지 않는다면 트랜잭션을 새로 시작한다. Propagtion.REQUIRES_NEW 매번 새로운 트랜잭션을 생성한다. 그렇다면 REQUIRES_NEW는 부모 트랜잭션에서 완전 독립적인 트랜잭션을 생성하는가 ? 꽤나 많은 곳에서 REQUIRES_NEW는 부모와는 아예 독립된 공간을 생성하는 것으로 표현되고 있고 나 역시 그렇게 알고 있었다. 독립된 공간은 부모 트랜잭션과 새롭게 생긴 자식 트랜..
나만의 코딩컨벤션 작성하기(Spring, Java, Naming, 구조, 코드 작성법 등) 현재(2020. 04) 나만의 코딩 컨벤션을 기록으로 남겨 계속해서 보완해나갈 생각이다. 물론 회사에서 하는 작업물은 나의 스타일과 안맞더라도 회사의 코딩컨벤션을 따르는 것이 맞다. 하지만, 회사의 컨벤션을 그냥 무심코만 따라하기만 하면 잘못된 스타일이 몸에 밸수도 있고 나의 스타일이 그냥 회사에 맞춰지게 된다. 나만의 코딩 컨벤션을 기록으로 남기고 꾸준히 보완해나갈 생각이다. 코딩컨벤션이란 어느 블로그에서 본 글인데, 가장 코딩컨벤션을 쉽게 표현한 것 같아 인용해서 설명하면 다음과 같다. 프로그래밍 언어는 한글, 영어, 일본어 등과 흡사하다. 한글에도 지역마다 사투리가 존재하고 그 지역에서 원활한 소통을 하려면 그 지역의 사투리를 잘 배우고 사용해야 한다. 이는 프로그래밍 세계에서도 마찬가지이다. 코딩..
[Spring] Retry 재시도 로직 구현하기 With Kotlin 서버를 운영하다보면 일시적인 오류가 종종 발생한다. 특히나 어플리케이션 간의 통신에서 이러한 일시적인 오류가 빈번하게 생기는 편이다. 이러한 오류는 재시도를 통해 문제가 해결되는 케이스가 대부분이다. 이를 위해 스프링에서는 `@Retryable` 이라는 어노테이션을 제공해서 해당 메소드 위에 어노테이션만 붙여주면 간단하게 재시도 할 수 있는 로직을 구현할 수 있다. 하지만 AOP 특성 상 어노테이션이 동작하기 위해서는 외부에서 해당 메소드를 호출해야한다. 고작 한줄만 재시도 로직이 필요한 상황인데, 그 한줄을 다른 클래스로 빼야되는 귀찮은 상황이 발생할 수 있다. 여기저기 Retryable 어노테이션이 붙어있는 것과 위에서 언급한 AOP의 단점을 보완하기 위해 특정 비즈니스 로직을 재시도할 수 있는 Re..
JPA 변경감지(Dirty Checking)과 OSIV JPA를 사용할 때 변경 감지를 주의해야한다. 아무런 생각없이 중간 데이터 전달 경로로 엔티티의 필드를 건드린다면, 실제로 DB에도 변경이 적용되기 때문이다. 또한 주의해야할 점은 OSIV를 활성화 시켰을 경우이다. 다음 예제를 살펴보자. fun test() { val product1 = productItemRepository.findById(1L).orElse(null) product1.amount = product1.amount + 1 // 엔티티 값 변경 // osiv가 활성화되어있다면 여기서 product1은 영속성컨텍스트에 계속 살아있게된다. (영속 상태) // osiv가 반대로 비활성화 되어있다면 여기서 product1은 영속성컨텍스트에 남아있지 않는다. (준영속 detach 상태) dirty..
JPA 영속성 컨텍스트의 1차캐시 & 쓰기지연은 정말 동작하는가? JPA는 엔티티를 영속성 컨텍스트에서 관리한다. 영속성 컨텍스트에 대한 장점을 다시 한번 살펴보면 다음과 같다. 1. 1차 캐시 2. 동일성 보장 3. 트랜잭션을 지원하는 쓰기 지연 4. 변경 감지 이러한 영속성 컨텍스트의 장점은 많이들 접해보고 들어봤을 것이다. 이 글에서는 1차캐시와 쓰기지연에 대해서 좀 더 자세히 알아보도록 한다. 1차 캐시 1차 캐시가 되는 것은 오직 식별자로 쿼리할 때만이 가능하다. 식별자가 무엇인가? 바로 @Id 어노테이션을 붙여둔 Key이다. 다음 예제를 살펴보자. Person(id = 1, name = "A") 위와 같은 Entity가 DB에 저장되어 있다고 가정해보자. 여기서 다음과 같이 쿼리를 하면 어떤 일이 발생할까? val p1 = repository.findByNa..