본문 바로가기

Spring Framework

(17)
[Spring] Spring은 DB 예외를 어떻게 바꾸는가 SQLException이 DataIntegrityViolationException이 되기까지 왜 예외 변환이 필요한가JPA를 쓰든 JDBC를 쓰든, 결국 DB와 통신하다 보면 예외가 발생한다. 유니크 제약 위반, 락 충돌, 연결 실패 등 다양한 상황이 있다. 문제는 이 예외들이 DB 벤더마다 형태가 다르다는 것이다.유니크 제약 위반 에러코드 MySQL → 1062 PostgreSQL → 23505 Oracle → 1 Hibernate나 JPA도 나름의 예외 계층을 갖고 있지만, DB 에러코드 수준의 세밀한 구분까지는 해주지 않는다. 결국 개발자가 PersistenceException을 잡아서 getCause()를 타고 내려가며 에러코드를 직접 파싱해야 하는 상황이 생긴다.Spr..
[Spring] Spring의 비동기 처리 — @Async부터 Virtual Thread 통합까지 들어가며이전 포스트에서 자바의 네 가지 동시성 구현 메커니즘(Thread, Executor, Fork/Join, Virtual Thread)을 살펴보았습니다. 이번 포스트에서는 Spring Framework가 이 위에서 비동기 처리를 어떻게 추상화하는지 정리합니다. Spring은 @Async 어노테이션 하나로 메서드를 비동기로 실행할 수 있게 해줍니다. 편리하지만, 내부 동작 원리를 이해하지 못하면 "분명히 @Async를 붙였는데 동기로 실행된다"는 문제를 마주치게 됩니다. 이 포스트에서는 설정부터 동작 원리, 흔한 함정, 그리고 Spring Boot 3.2+에서의 Virtual Thread 통합까지 다룹니다. 1. @Async와 ThreadPoolTaskExecutor 설정1-1. @EnableAsyn..
[Spring Security] Spring Security 환경에서 CORS 제대로 이해하고 설정하기 CORS란?CORS(Cross-Origin Resource Sharing)는 브라우저가 현재 페이지의 출처(Origin)와 다른 출처로 HTTP 요청을 보낼 때 적용되는 보안 정책이다. 여기서 Origin이란 프로토콜 + 호스트 + 포트의 조합을 말하며, 이 중 하나라도 다르면 Cross-Origin으로 간주된다. 예를 들어 프론트엔드가 http://localhost:3000, 백엔드가 http://localhost:8080이면 포트가 다르므로 Cross-Origin이다. 중요한 점은 CORS는 서버가 아닌 브라우저가 적용하는 정책이라는 것이다. 서버 간 통신이나 Postman 같은 도구에서는 CORS가 적용되지 않는다. 브라우저가 서버의 응답 헤더를 확인해서 "이 Origin에서의 요청이 허용됐는가?"..
[Spring] Spring MVC + Tomcat vs Spring WebFlux + Netty, 그리고 Virtual Thread까지 Spring 기반 웹 애플리케이션의 동시성 모델을 비교하고, JDK 21의 Virtual Thread가 가져온 패러다임 변화를 정리합니다.1. 두 가지 동시성 모델Spring MVC + Tomcat: Thread-per-RequestSpring MVC는 thread-per-request 모델을 사용한다. 요청이 들어오면 Tomcat의 스레드 풀(기본 200개)에서 스레드 하나를 할당하고, 해당 스레드가 컨트롤러 → 서비스 → DB 호출까지 전부 담당한다. DB I/O 같은 블로킹 작업이 발생하면 해당 스레드는 응답이 올 때까지 대기(blocking) 상태에 놓인다. Spring WebFlux + Netty: Event LoopSpring WebFlux는 Event Loop 모델을 사용한다. Netty의 ..
[Spring Boot] 커스텀 프로퍼티 완벽 가이드 개요Spring Boot 개발을 하다 보면 하드코딩된 값들로 인해 고민을 하게 된다."이 설정값을 바꾸려면 또 코드를 수정하고 배포해야 하나?" 라는 생각이 들 때가 종종 생긴다. 이런 문제를 해결해주는 것이 바로 커스텀 프로퍼티이다.이 글에서 커스텀 프로퍼티가 무엇인지, 어떻게 사용하는지, 그리고 언제 사용해야 하는지에 대해 자세히 알아보자. 1. 커스텀 프로퍼티란?커스텀 프로퍼티는 애플리케이션에서 필요한 설정값들을 application.properties 또는 application.yml 파일에 정의하고, 이를 Java 코드에서 사용할 수 있도록 하는 Spring Boot의 기능이다. 간단한 예시로 시작해보자:# application.propertiesspring.application.name=d..
[Spring] Spring 캐시(Cache) 핵심정리 개요채팅 시스템을 프로젝트에서 구현하면서 Redis를 프로젝트에 도입하게 되었다.Redis는 채팅방 구독 정보를 관리하기 위해 도입했지만, 캐싱도 가능하다고 글을 읽은 적이 있다. 캐싱을 적용한 곳은 채팅방 목록에서 마지막 메시지 조회 로직이었고,직렬화, 역직렬화 문제로 나름 애를 먹었지만 잘 도입할 수 있었다! 1. 캐시 어노테이션 3종 세트@Cacheable - 조회 시 캐싱@Cacheable(value = "userCache", key = "#userId")public User getUser(Long userId) { return userRepository.findById(userId); // 첫 번째만 실행, 이후 캐시 반환} @CachePut - 업데이트하면서 캐시 동기화@CachePut..
[Spring Boot] 환경별 설정 어떻게 해야할까? 개요 저번 팀 프로젝트에서는 application.properties에 spring.profile.include=secret을 적고,github에 공유하지 않는 application-secret.properties를 통해 비밀값들을 관리했었다.그리고 배포 과정에서 Github Secrets를 사용해 그 값들을 암호화했다. 그런데 실전 스프링부트 책을 읽으며 이런 방식말고도 환경 변수를 이용하는 방법과local(로컬), dev(개발), prod(운영)별로 세팅을 다르게 하는 방법을 알 수 있었다. 환경 변수로 비밀을 관리하는 건 어렵지 않으니환경별 세팅하는 방법에 대해 자세히 알아보자!! 1. Profile을 통해 환경별 설정하기먼저 Profile을 통해 환경별로 설정하는 걸 배워보자. Profile 방..
[Spring Boot] 스프링 부트 이벤트 리스너 구현과 등록 개요 실전 스프링 부트 책을 읽으며,스프링에 이벤트와 이벤트 리스너가 존재한다는 사실을 알게 되었다. 리스너의 구현 방식과 등록 방법에 대해서 정리해보고자 이 포스트를 작성한다. 1. 이벤트 리스너 구현 방법1. @EventListener 어노테이션 방식 (Spring 4.2+)@Componentpublic class MyEventListener { @EventListener public void handleApplicationReady(ApplicationReadyEvent event) { // 처리 로직 } @EventListener public void handleContextRefresh(ContextRefreshedEvent event) {..