[Test] DataSource Bean & properties(yaml) & SQLGrammarException: could not prepare statement [Table ~~ not found]
·
JAVA/Application
■ 단일 DataSource 설정properties/yaml에서 db connection 설정 방법은 이렇다.spring.datasource.properties.driverClassName=...spring.datasource.url=...spring.datasource.username=...spring.datasource.password=... 하지만 만약 멀티 데이터소스 요구사항이 다른 경우, 위와 같은 properties에 따른 기본적인 DataSource가 필요한 것이 아니라, 별도로 구현해둔 빈이 필요할 수 있다. (🔗 예를 들면 이런 상황) 그리고 그런 커스텀 DataSource를 사용하도록 테스트 환경을 구성할 때 어떻게 DataSource와 DB 접속 정보를 설정해야 하는지, 놓칠 수 있..
MDC를 사용해 멀티쓰레드 로깅하기 (for 쓰레드간 Context 전달)
·
JAVA/Application
■ Intro멀티쓰레드 환경의 비동기 로깅을 해야했고, MDC를 활용했다.상황을 설명하자면 요청 경로는 동일하게 들어오지만 중간에 쓰레드가 나뉘는 코드가 있었는데, 요청의 컨텍스트를 유지하고 있어야 했다. 예를들어 처리시간을 로깅하려면 처리시작 시간을 보유하고 있어야 어디선가 처리가 끝날 때 총 처리 시간을 구할 수 있다. 비동기일 경우 처리가 끝나는 시점을 모르기 때문에, 그런 최적의 방법에 대한 고민이 필요했다. 결론적으로 MDC + TaskDecorator + AOP를 통해서 구현했다. 비동기 처리의 완료시점을 확실히 하는 것이 중요하므로 MDC를 사용하여 쓰레드를 트래킹하는 것이 적절해보였다. TaskDecorator가 MDC 컨텍스트를 분기 대상 쓰레드로 넘겨서 종료시점까지 정보를 유지하려는 방..
[Springboot] 스케줄러 동적 등록/삭제/변경
·
JAVA/Application
■ Intro동적으로 스케줄링 정보를 변경해야 할 일이 있다. 예시로 스케줄링 주기를 중간에 바꿔야 한다든가, 스케줄 내용을 변경해야 한다든가 말이다. 값이 동적으로 들어오는 위치를 DB라면, DB의 데이터 변경을 자동으로 알아차린 후 스케줄러를 변경시켜야 한다. 그래서 지난 번에는 어떻게 변경감지를 할지 고민했었고, 폴링으로 감지하기로 결정했다. 이번에는 데이터 변경이 감지된 후 스케줄러를 동적으로 변경하는 방법을 정리하겠다. ■ 샘플 구조예시로, 1분마다 DB에서 '주기 값'이 변경되었는지 확인하고, 스케줄러에 반영하는 간단한 샘플 구조를 작성했다. 각자의 비스니스에 맞게 커스텀해서 사용하면 될 것이다. @Componentpublic class SampleDynamicScheduler {    pri..
[Spring] DTO 매핑시 특정 키만 null 값
·
JAVA/Application
나머지 값들은 다 정상적으로 매핑되어 값이 잘 들어가는데, 특정 키만 null로 들어가는 것을 발견했다.원인은 필드명이었다. 아래 글 덕분에 알게 되었다. https://bcp0109.tistory.com/309 Spring Request DTO 에 null 값이 들어가는 이유 (Jackson, Lombok)Overview Spring Boot 로 REST API 를 테스트 하다가 이상한 이슈에 직면했습니다. 클라이언트에서 @RequestBody 로 요청을 받기 위한 DTO 클래스를 만들고 값을 입력 받았는데 null 값이 입력되는 겁니다. 처bcp0109.tistory.com  문제가 되는 필드명은 cId였다. 소문자 하나 다음에 바로 대문자가 나오는 필드명이 문제가 되는 것이다. Spring은 htt..
[Spring AOP] Consumer onMessage() 비동기 수신 로깅
·
JAVA/Application
■ AOP를 통해 onMessage() 비동기 수신 로깅 Redis가 Consume할 때 호출되어 작업을 처리하기 시작하는 부분인 onMessage() 메서드를 AOP를 통해 로깅하려는 상황이었다. 기능 구현을 위한 샘플 코드를 짜서 테스트해보았다. 구조는 이러하다.- ConsumerFactory: 메시지를 구독할 컨슈머들을 생성- StreamListenerImpl: 구독한 메세지를 처리할 onMessage 구현- ListenContainer: 위 리스너를 관리할 컨테이너 설정- LoggingAspect: 테스트 대상인 Aspect들- RedisConfig: 기본 레디스 설정  *참고: ListenerContainer, Listener, 그리고 Consumer 객체간의 관계를 이해하는 것이 필요하다면, ..
[Redis] cannot deserialize from Object value (SerializationException)
·
JAVA/Application
Springboot Cache를 적용하고자 할 때 발생가능한 오류입니다.- 저는 redis cache 사용했습니다.- 또한 캐시 value에 대해서 GenericJackson2JsonRedisSerializer를 적용했습니다. 서버에 캐시를 적용했는데 만약 이런 에러를 만났다면, jackson의 역직렬화에 대해 생각해봅시다.캐시된 응답을 올바른 객체로 내보내야 하는데 역직렬화할때 쓸 생성자가 없다면cannot deserialize from Object value를 로그에서 만날 수 있습니다.*생성자의 존재 문제가 아닌, 역직렬화하기 적절한 생성자를 두는 것이 핵심입니다.org.springframework.data.redis.serializer.SerializationException: Could not ..
다량의 이미지 업로드 속도 최적화 / 트래픽 대비 / 비동기 처리
·
JAVA/Application
■ 리뷰등록시 문제 가능성너무나도 희망찬 이야기겠지만,만약 우리 서비스의 인기가 폭발해서동시에 많은 유저가 사진리뷰를 업로드한다면 어떨까? 동기적으로 처리할경우 대용량 사진 업로딩이 하나라도 있다면, 뒤를 이을 수많은 업로딩이 블로킹되며 작업이 주르륵 지연된다. 그래서 이때는 비동기 처리를 생각해야 한다.  이 상황을 대비하고자 하여..문제의 코드를 수선해봤다.  ■ 성능 측정 (TPS)2초 안에 25건의 스레드(사용자)를 실행함 (= 약 0.08초마다 스레드를 순차 실행)각 스레드(사용자)는 요청을 총 4개 보냄(= 총 100건의 요청을 보내는 테스트) □ 변경 이전  □ 변경 이후전반적으로 TPS도 상승하고,처리시간도 약 0.65배로 단축했다.  "> □ 비동기 + Multipart 관련 문제 해결사..
[Spring] Cache : 프로젝트에 간단히 적용해둠
·
JAVA/Application
우리 서비스에서 일관된 데이터를 불러올 때 쿼리가 나가거나 재계산하는 것이 거슬려서 이번에 스프링 캐시를 도입해봤다. 스프링은 캐시 기능을 제공한다. 스프링 캐시 기능은 트랜잭션처럼 AOP를 통해 구현했기에 어노테이션을 사용하면 된다. 일단 간단히 어노테이션만 추가해뒀다. 현업에서 EhCache, Redis, Memcached를 많이 사용하는 것 같은데 일단은 나중에 공부 및 개선하도록 하고, 이번에는 찍먹해볼 겸 어노테이션을 통한 기본기본 캐시만 해보겠다...일단 평점이랑 메뉴정보만 캐시해뒀다.곧 코드 구조도 리팩터링 예정이라.. 남은 리뷰캐시는 그때 다시 생각해보기로 한다.이제 로그에 잡다한 쿼리문이 안 보여서 좋다. 🪄공부✨ 캐시 저장소두가지 구성방식이 있다. 하나는 JVM ..
[Java][Backend] null 반환 리팩터링
·
JAVA/Application
계기: 간만에 이펙티브자바 복습했다. 아래 내용을 프로젝트에 적용해보기로 결정했다! https://splendidlolli.tistory.com/672 [이펙티브 자바] null이 아닌, 빈 컬렉션이나 배열을 반환하라 ─ 8장:메서드:Item54 null이 아닌, 빈 컬렉션이나 배열을 반환하라 null이 아닌 빈 배열이나 컬렉션을 반환하라. null을 반환하는 API는 사용하기 어렵고, 오류 처리 코드도 늘어난다. 그렇다고 성능이 좋은 것도 아니다. splendidlolli.tistory.com 🪄 리팩터링 케이스 1. return값을 사용하지 않는데 null 반환을 금지해야 할까? 아래와 같이 리턴값을 사용하지 않는 메서드라도, null을 반환하지 않게 했다. (코드의 일관성, 미래의 안정성을 근거로 ..
[Spring] AOP로 편리하게 jwt token 검증하기
·
JAVA/Application
🪄 발단카카오 로그인을 구현하면서 클라이언트로부터 token 값을 넘겨받는 api가 많이 생겼다. 현황은 이 token을 검증하지 않고 있었다. 그러나 안전한 서비스를 제공하기 위하여 우리가 가진 jwt secret key로 token을 검증할 필요가 있어보였다. 그래서 오늘 실행에 옮겼다. 사실 지금처럼 검증하지 않더라도 유효하지 않은 token이 넘어올 경우 그냥 개인정보를 제공하지 않도록 처리되어있어서 현재 우리 서비스에 token 검증은 필요하지 않을 수 있다고 생각할 수 있다. 그렇지만, 유효하지 않은 토큰이 넘어올 경우에 대한 관리를 일관된 장소에서 할 수 있다는 장점이 있다고 보았다. 더 나아가, 유효하지 않은 token일 경우에 수행되지 않아도 될 불필요한 비즈니스 로직, 디버깅 비용을 ..