개요 Spring에서 유효성 검증을 위해서 사용되는 어노테이션에는 흔히 @Valid와 @Validated가 있다. 필자는 평소에는 @Valid 위주로 사용했는데, 얼마 전 진행했던 프로젝트에서 @Validated를 사용한 좋은 검증 예시를 보아서 정리해보고자 한다. @Valid 먼저 @Valid는 jakarta.validation(이전에는 javax.validation), 즉 Java 라이브러리 안에 속해있는 어노테이션이다. @Valid 어노테이션은 Bean Validation API와의 통합을 통해서 데이터 무결성을 유지하는 데에 필요한 유효성 검사를 수행할 수 있다. Bean Validation API란?@NotBlank, @Min, @Email과 같이 도메인 모델의 필드에 유효성 제약을 위한 어..
부제) 필터에서 multipart/form-data 읽기 개요 갑자기 뜬금없는 주제로 글을 쓰게 됐는데, 최근에 진행했던 프로젝트에서 겪었던 문제를 해결하는 과정에서 알게 된 내용이라 까먹기 전에 정리해두려고 한다. 첫 번째 문제 - request body (사실 피할 수 있던 문제였기는 했지만 내가 해보고싶어서 시작해버림) 시작은 Spring AOP를 사용한 로깅 시스템의 도입이었다. 프로젝트에 타 동아리에서 봤던 Admin페이지에 요청 정보를 로깅하는 시스템을 그대로 도입해보려고 했는데, 나는 요청을 인터셉터하는 위치를 필터로 정했다. 이를 위해서 Filter에서 HttpServletRequest를 인터셉트하여 정보를 Mdc에 저장할 계획이었다. OncePerRequestFilter를 통해서 매..
자바의 비동기 자바에서 비동기 처리를 위해서는 쓰레드를 생성한 후 작업을 할당하는 방식을 주로 사용한다. 첫번째로 Thread 클래스를 상속받고, 상속받은 클래스에서 run()메서드를 오버라이딩해주는 방법이 있고, 두번째로는 Runnable 인터페이스를 구현하는 클래스를 정의하고 해당 클래스를 Thread의 생성자 파라미터로 전달하는 방법이 있다. 방법 1 - Thread 상속하기static class MyThread extends Thread { @Override public void run() { System.out.println("Thread: " + Thread.currentThread().getName()); }}void threadStart() { Thread..
Batch와 Spring Batch Spring Batch는 배치 작업을 위해서 스프링에서 제공하는 배치 프레임워크이며, 배치(Batch)란 데이터를 실시간으로 처리하지 않고 단발성으로 일괄처리하는 방식을 말한다. 상품 결제를 승인하거나 api요청에 따라 뷰를 띄워주는 등의 작업을 위해서는 클라이언트에게 즉각적인 응답을 제공해야 한다. 하지만 일정 시간을 기준으로 데이터를 취합하여 통계 리포트를 생성하거나, 부하가 큰 대용량의 데이터 작업을 서버 부하가 적은 특정 시간대에 처리하려 할 경우에는 실시간 처리보다는 특정 주기를 두고 처리하는 것이 바람직하다. 이러한 데이터 처리 방식을 배치(Batch)라고 한다. 이러한 배치 어플리케이션의 특성에 Spring Framework의 3대 요소인 DI, AOP,..
개요 예전 JPA를 처음 공부하던 시절에 '프록시'라는 개념을 접한 적이 있고, 구조 패턴 중 하나인 프록시 패턴과 데코레이터 패턴에 대해서 공부했던 적이 있다. 이처럼 스프링 환경의 다양한 곳에서 프록시가 사용되고 있다는 것은 들어본 적이 있는데, 지금까지는 @Transactional 사용시 스프링이 트랜잭션 대상 코드를 프록시 형태로 감싼다는 정도로만 알고 있었다. 이번 포스트에서 프록시에 대한 개념부터, 스프링이 프록시를 어떻게 활용하고 있는지에 대해서 자세하게 정리해보도록 하겠다. 동적 프록시 타겟 클래스 하나마다 프록시 클래스를 직접 생성하여 적용하는 방법을 정적 프록시라고 한다. 프록시의 사용 목적이 접근 제어나 기능 추가와 같이 공통 코드의 반복이라는 점을 고려하면, 프록시 적용 대상이 되..
배경지식 Spring Boot에서 json으로 rest api 통신을 하기 위해서 DTO를 이용하는데, http통신시에 직렬화, 역직렬화되는 과정에 대해서 원래 다음과 같은 사실들을 알고 있었다. - 직렬화, 역직렬화를 위해서 Jackson이라는 라이브러리가 많이 사용되며, Jackson 내부에서는 ObjectMapper가 Java Reflection을 사용한다. - Jackson이 직렬화, 역직렬화를 하기 위해서는 DTO에 default constructor와 getter, setter가 필요하다. Default constructor를 통해서 객체 접근/생성이 이루어지고, getter와 setter를 통해서 field들에 대한 접근이 이루어진다. - Setter를 사용하게 되면 객체의 불변성을 유지할 ..
개요 스프링 시큐리티를 사용하여 프로젝트를 디벨롭하다 보면, 회원가입이나 로그인시에는 시큐리티 필터를 통과할때 인증,인가 프로세스에서 제외하거나, 아예 시큐리티 필터를 타지 않도록 만들어야 한다. 그런데 사실 이런 경우를 제외하고도 로그인이 필요하지 않은 뷰에 필요한 api를 제작할 때 처럼, 시큐리티 필터에서 별도의 인증을 수행하지 않는 요청을 관리해야 하는 경우가 있다. .authorizeHttpRequests(authorize -> authorize .requestMatchers("/auth/**").permitAll() // 로그인 필요 X .requestMatchers(HttpMethod.GET, "/test/**").permitAll() // anonymousUser 테스트 .anyReques..
개요 트래픽이 많아질수록 동시성 이슈를 철저하게 고려해야 한다.자바 스프링에서 발생할 수 있는 동시성 이슈를 체크하고, 다양한 해결방법에 대해서 공부해보자. 동시성 문제는 지역변수와 같이 쓰레드별로 할당되는 공간에서는 발생하지 않으며, 싱글톤과 같이 동일한 인스턴스의 필드에 접근하거나, static과 같은 공용 필드를 변경할 때 발생한다. 위와 같이 간단한 엔티티와 서비스 클래스를 생성해준 후, 재고를 감소시키는 decrease라는 로직이 동시성 이슈 위에서 제대로 동작하는지를 체크해보도록 하자. 가장 먼저 들었던 생각은 그냥 "@Transactional 어노테이션 걸어주면 되는거 아니야?"라는 단순한 생각이었다. 트랜잭션을 통해서 데이터의 무결성을 지킬 수 있지 않을까? 라는 생각으로 간단한 테스..
동기와 비동기 스프링에서는 @Async 어노테이션을 이용한 비동기 호출을 지원한다. 동기 호출은 일반적인 코드 흐름으로, 코드의 순서에 따라서 순차 처리되는 일반적인 플로우를 말한다. 반면 비동기 호출은 현재 실행중인 코드의 흐름과는 상관없이, 완료 여부를 확인하지 않고 다음 로직으로 넘어가는 것을 말한다. (동기 시퀀스 다이어그램) 동기 호출의 예시인데, ServiceBus에서 메시지가 반환될때까지 TBJump 정보를 조회하는 플로우는 실행되지 않는다. (비동기 시퀀스 다이어그램) 이번에는 비동기 호출의 예시이다. 처음 보낸 요청의 결과를 확인하지 않고, 두번째 로직을 실행하는 모습을 볼 수 있다. 동기 호출은 코드의 이해와 설계가 쉽지만, 많은 요청을 반복적으로 처리해야 하거나, 요..
개요 작년에 스프링 시큐리티를 처음 공부했을 때(https://eckrin.tistory.com/103) 시큐리티 구조와 초기 설계에 대해서 글을 썼던 적이 있는데, 실제로 사용하면서 궁금했던 점들을 정리해보고자 한다. SecurityFilterChain과 WebSecurityCustomizer 먼저 시큐리티 설정을 위해서 Configuration 파일을 만들 때 httpbasic, csrf, cors 등 다양한 설정을 했는데, 그 중 antMatchers(스프링 3.x버전에서는 requestMatchers로 대체)를 사용하는 SecurityFilterChain과 WebSecurityCustomizer에 대한 설명을 해보고자 한다. SecurityFilterChain에서는 특정 경로로 들어오는 요청 패턴..
개요 스프링 프레임워크가 처음 출시되었을 때는 의존성 버전을 직접 관리하거나, 서버를 직접 설치해주어야 하는 등의 초기 설정을 직접 해주어야 했다. 이를 보완하기 위해서 스프링 부트가 출시되었는데, 이것은 최소한의 설정으로 스프링 기반의 애플리케이션을 독립 실행할 수 있게 돕는 프레임워크라고 할 수 있다. 우리는 스프링 부트를 통해 1. starter 패키지를 통해 필요한 의존성을 자동으로 가져올 수 있게 되었을 뿐 아니라,2.기존에는 @ComponentScan, @EnableAutoConfiguration, @Configuration을 통해서 명시적으로 설정해주어야 했던 반면, @SpringBootApplication을 통해서 이 셋 대신 자동으로 필요한 빈을 설정해줄 수 있게 되었다.3. 또한, 내..
스프링 시큐리티와 jwt를 이용하여 api를 개발할때, 사용자의 정보를 제대로 전송하기 위해서는 크게 @AuthenticationPrincipal 어노테이션을 이용하여 인증이 필요한 요청마다 SecurityContextHolder에 저장한 인증값을 가져오는 방법도 있고, HandlerMethodArgumentResolver를 이용하여 토큰에서 인증값을 가져오는 클래스를 직접 만드는 방법이 있다. @AuthenticationPrincipal 사용하기 @AuthenticationPrincipal 어노테이션을 사용하면 UserDetailsService의 loadUserByUsername을 통해서 return한 객체(UserDetails)를 파라미터로 직접 받아서 사용할 수 있다. @PostMapping("/c..