🔥스파르타 TIL (Spring) 23

동시성 제어에 Redisson과 Lua Script 사용해보기

Redisson은 Java 기반의 Redis 클라이언트 라이브러리로, Redis의 다양한 기능을 Java 객체 형태로 쉽게 사용할 수 있도록 추상화 계층을 제공합니다. 이를 통해 분산 락, 트랜잭션, 캐싱, pub/sub 등 Redis의 고급 기능을 활용하여 분산 시스템을 구축할 수 있으며, Netty 기반의 비동기 방식으로 높은 성능을 자랑합니다.Lua Script는 경량의 고급 프로그래밍 언어인 Lua를 Redis에서 사용할 수 있도록 해주는 기능입니다. Redis는 기본적으로 한 줄씩 단일 명령어를 처리하는 방식으로 동작하지만, Lua Script를 사용하면 Redis 내에서 여러 명령어를 하나의 원자적 작업으로 처리할 수 있습니다. 현재 시스템에서는 선착순 쿠폰 발급 기능을 구현하기 위해 Redi..

MapStruct 사용해보기

MapStruct는 DTO와 엔티티 간의 변환 작업을 자동화하는 도구이다.중복 코드 제거: DTO와 엔티티 간 변환이 여러 군데에서 필요할 때, 수작업으로 변환 메서드를 작성하는 것보다 자동으로 변환을 처리해주어 코드 중복을 줄일 수 있다.성능 최적화: MapStruct는 컴파일 시점에 변환 코드를 생성하기 때문에 런타임 성능에 큰 영향을 주지 않으며, Reflection을 사용하는 방식보다 훨씬 빠르다.유지보수성 향상: 변환 로직이 변경될 경우, 일관되게 관리되기 때문에 코드의 유지보수가 용이하다. MapStruct – Java bean mappings, the easy way!MapStruct Spring Extensions 1.1.3 released March 14, 2025 It is my ple..

커스텀 어노테이션과 AOP를 사용해서 권한 체크해보기

AOP (Aspect-Oriented Programming, 관점 지향 프로그래밍) : 프로그램의 핵심 로직과는 별개로, 공통적으로 반복되는 부가적인기능(관심사)을 한 곳에 분리해서 모듈화하는 프로그래밍 방식 AOP Concepts :: Spring FrameworkLet us begin by defining some central AOP concepts and terminology. These terms are not Spring-specific. Unfortunately, AOP terminology is not particularly intuitive. However, it would be even more confusing if Spring used its own terminology. Arou..

Redis를 활용한 BlackList 관리 중 깨달은 문제

access_token이 노출이 되었다는 가정하에 BlackList에 등록해주는 기능을 구현하던 중 아무생각 없이 Redis에 저장하는 시간을 대충 저장하게 되면서 깊은 생각에 빠지게 되었다. access_token을 Redis에 BlackList로 저장한 뒤, 만료시간을 사용자 정의로 지정해주면서 실제 BlackList에 등록된 access_token이 언제까지 유효한지 알 수 없다는 생각이 들면서 개선해보기로 마음을 먹었다.Beforeaccess_token을 BlackList로 관리하는 과정에서 임의로 1시간으로 지정함.1. BlackList에 등록된 access_token이 언제 만료되는지 알 수 있는가?2. BlackList에 등록된 access_token의 만료 시간이 BlackList에 등록된..

Transaction 이란?

데이터베이스 데이터들의 무결성과 정합성을 유지하기 위한 것으로 데이터를 안전하게 관리하기 위해서 생겨난 개념이다.여러 작업을 하나의 작업으로 묶어서 처리하는 것으로 Commit, Rollback을 알아보자. 트랜잭션의 4가지 특징 ACID Atomicity (원자성) : 트랜잭션은 모두 실행되거나, 전혀 실행되지 않아야 한다. ex) 송금 과정에서 계좌에 돈이 빠져나갔지만 상대 계좌로 입금이 안되면 안 된다.Consistency (일관성) : 트랜잭션이 완료되면 데이터는 일관된 상태를 유지해야 한다. ex) 은행 계좌에서 100만 원이 빠져나가면, 전체 은행 시스테의 총금액은 변하면 안 된다.Isolation (격리성) : 여러 트랜잭션이 동시에 실행되더라도 서로 영향을 주면 안 된다. ex) 두 명이 ..

JPA Auditing 이란?

데이터의 생애 주기(Lifecycle)를 추적하고 관리하기 위해 사용할 수 있다. JPA Auditing과 LocalDateTime을 사용하면 각 엔티티의 생성, 수정, 삭제 시점과 같은 중요한 정보를 자동으로 기록하고 관리할 수 있다. 엔티티의 수명 동안 언제 생성되고 수정되었는지 추적하는 것은 시스템의 변경 내역을 관리한다. 예를 들어, 사용자가 데이터를 수정하거나 새로운 엔티티를 추가할 때, 데이터가 언제 어떻게 변경되었는지 알 수 있어서 문제가 발생한 시점이나 원인을 추적하는 데 용이하고, 누가 언제 데이터를 변경했는지 기록할 수 있어서 보안 감사, 법적 요구사항 등을 충족하는 데 필요할 수 있다.데이터의 생성일과 수정일을 추적하면, 더 이상 사용되지 않는 오래된 데이터를 쉽게 식별할 수 있어서 ..

IoC 컨테이너 활용: 생성자 주입과 빈 조회 방식

객체의 불변성을 유지하기 위해 변수를 final로 선언하며, 해당 변수를 즉시 초기화하거나 생성자를 통해 주입하는 방식을 사용한다. 생성자 주입은 객체 생성 시점에 의존성을 명확히 하고, 테스트 용이성과 코드 가독성을 높이는 장점이 있다. @Autowired 어노테이션을 사용하면 IoC 컨테이너에 의해 관리되는 빈을 주입받을 수 있다. 하지만 자동 의존성 주입으로 인해 객체 간 명시적인 의존관계가 모호해질 수 있고, 반드시 스프링 IoC 컨테이너에서 관리되는 빈 클래스에만 사용이 가능하기 때문에 추천하지 않는 방식이다. 수동으로 직접 IoC 컨테이너에 접근해서 빈을 가져오는 방법을 살펴보자 ApplicationContext context : 빈 팩토리 등등의 클래스들을 상속받은 클래스. IoC 컨테이너라..

동기(Sync)와 비동기(Async)란?

동기 : 만약 어떤 함수 X가 동기로 함수 Y를 호출하면, X는 Y의 작업이 완료될 때까지 기다려야하는 순차적인 진행이다.비동기 : 함수 X가 비동기로 함수 Y를 호출하면, X는 Y의 작업을 신경쓰지 않고 따로 동작하는 병렬적인 진행이다. Spring에서는 기본적으로 동기적으로 처리되지만, 비동기가 필요한 경우에는 @Async 어노테이션을 사용하여 구현할 수 있다. 동기 ▼@GetMapping("/task")public String syncTask() throws InterruptedException { System.out.println("동기 작업 시작"); Thread.sleep(3000); // 3초 동안 대기 System.out.println("동기 작업 완료"); retur..

Pageable을 알아보자

데이터베이스에 수천 건이나 수만 건의 데이터가 존재할 때, 모든 데이터를 한꺼번에 조회하여 클라이언트로 전송하는 것은 네트워크 부하를 증가시키고, 애플리케이션의 성능 저하를 발생시킬 수 있다.  이러한 문제를 피하기 위해 페이징(Paging) 기법을 사용하여 필요한 데이터만 일정한 크기로 나누어 조회하고 전송함으로써 네트워크 트래픽을 최적화할 수 있다.  페이징을 사용하는 예시 ▼ @GetMapping("/products") public Page getProducts( // 페이지, 사이즈, 정렬, 오름차순 @RequestParam("page") int page, @RequestParam("size") int size, ..

QueryDSL 이란?

하이버네이트 쿼리 언어의 쿼리를 타입에 안전하게 생성 및 관리해주는 프레임워크로, 자바 백엔드에서 Spring Data JPA를 함께 사용한다. 하지만 JPA로 복잡한 쿼리, 동적 쿼리를 구현하는데 한계가 있기 때문에 이를 해결할 수 있는 것이 QueryDSL 이다.Mybatis, JPQL 등 문자열 형태로 쿼리문을 작성하여 컴파일 시에 오류를 발견하는 것이 불가능했지만, QueryDSL은 자바 코드로 SQL문을 작성할 수 있기 때문에 컴파일 시에 발생하는 오류를 확인할 수 있다. 예를 들어서 복잡한 검색 조건이 있다고 가정해보자public interface MemberRepository extends JpaRepository { // 이름이 포함되고, 특정 나이 이상이며, 특정 지역에 사는 활..