Spring 기술 면접 분석
기술 면접 대비 핵심 질문
카테고리: Spring
Q. Spring의 IOC(제어의 역전)와 DI(의존성 주입)에 대해 설명해주세요.
핵심 답변
IOC(제어의 역전)란 객체의 생성부터 소멸까지 클래스 내부에서 개발자가 직접 new로 관리하던 흐름을 프레임워크인 Spring Container에게 넘기는 설계 원칙입니다. DI(의존성 주입)는 이러한 IOC를 구현하는 구체적인 디자인 패턴 중 하나로, 객체에 필요한 의존성을 외부 컨테이너(ApplicationContext)가 주입해주는 방식을 뜻합니다. 이를 통해 결합도를 낮추고 유연성과 테스트 용이성을 높일 수 있습니다.
꼬리 질문
- Q. Spring에서 DI를 주입받는 세 가지 방식과 권장되는 방식은 무엇인가요?
- A: 필드 주입(Field Injection), 수정자 주입(Setter Injection), 생성자 주입(Constructor Injection) 세 가지가 있습니다. 이 중 스프링 공식 문서에서 제일 권장하는 방식은 생성자 주입으로, 순환 참조를 시작시점에 감지할 수 있고 필드를
final로 선언하여 불변성을 보장할 수 있기 때문입니다.
- A: 필드 주입(Field Injection), 수정자 주입(Setter Injection), 생성자 주입(Constructor Injection) 세 가지가 있습니다. 이 중 스프링 공식 문서에서 제일 권장하는 방식은 생성자 주입으로, 순환 참조를 시작시점에 감지할 수 있고 필드를
Q. IoC와 DI의 개념을 설명해주세요.
핵심 답변
IoC(제어의 역전)는 객체의 생명주기 관리와 흐름의 권한을 프로그래머가 아닌 스프링 컨테이너(Spring Container) 등의 외부가 통째로 뺏어가 대신 책임지는 핵심 개발 방법론을 뜻합니다. DI(의존성 주입)는 그 구체화 중 하나로, 생성될 A 스레드가 내부에서 필요한 B 부속 객체를 자기가 직접 new하지 않고 밖에서 구동 컨테이너가 꽂아넣어주어 철저하게 의존성을 낮추는 패턴입니다.
꼬리 질문
- Q. DI의 방식 중 가장 현재 스프링에서 강력하게 권장되는 방식은?
- A: 필드 주입이나 Setter를 피하고 **생성자 주입(Constructor Injection)**을 최우선하는 것입니다. 생성자 사용 시
final키워드 등록으로 철저한 불변성을 지킬 수 있고 컴파일 타임에 즉각적인 순환 참조 감지가 가능하다는 장점이 큽니다.
- A: 필드 주입이나 Setter를 피하고 **생성자 주입(Constructor Injection)**을 최우선하는 것입니다. 생성자 사용 시
Q. Spring Boot와 Spring의 차이는?
핵심 답변
스프링 부트는 기존 막강하지만 수십 종의 지옥같은 XML 설정이 불가피하던 스프링 프레임워크를 기반으로, 빠르고 막힘 없는 프로덕션 세팅에 돌입하기 위해 만들어진 초강력 상위 호환 도구입니다. 복잡한 라이브러리 의존성 버전을 묶어 자동 관리해주고(.starter), 내장 웹서버(Tomcat 등) 가 기본 삽입되어 있어 불필요하던 .war 빌드나 톰캣 별도 다운로드 구성 작업 전부를 통째로 증발시키는 편의성을 달성했습니다.
꼬리 질문
- Q. 스프링 부트에 내장된 주요한 기능이자 원칙인 AutoConfiguration(자동 구성) 원리는 무엇인가요?
- A: 개발자가 특별히 명시 설정하지 않더라도 컨테이너 환경의 클래스 패스에 존재하는 관련 라이브러리들을 일일이 추적 판단해, 애플리케이션 가동 시
@EnableAutoConfiguration체제에 의해 일상 구동될 상식선 설정들을 지가 알아서 싹 다 구성하고 띄워주는 최강의 오버라이드 규약 기법입니다.
- A: 개발자가 특별히 명시 설정하지 않더라도 컨테이너 환경의 클래스 패스에 존재하는 관련 라이브러리들을 일일이 추적 판단해, 애플리케이션 가동 시
Q. @Transactional 애노테이션의 동작 방식과 주의할 점은?
핵심 답변
@Transactional은 Spring AOP(프록시)를 통해 동작합니다. 메서드 호출 전 프록시가 가로채 트랜잭션을 시작하고, 로직 통과 후 커밋하며 만약 런타임 예외(Unchecked Exception)가 터지면 자동으로 롤백시킵니다. 주의할 점은 '동일 클래스 내부 메서드 호출' 시에는 프록시 객체를 타지 않고 This(원본 객체)로 직접 접근하기 때문에 트랜잭션이 아예 발동하지 않는 치명적 한계(Self-Invocation)가 있다는 것입니다.
꼬리 질문
- Q. Checked Exception(
IOException등)이 발생해도 롤백이 되나요?- A: 기본 속성상 Checked Exception은 롤백되지 않고 커밋해버립니다. 따라서 서비스 상 컴파일 예외를 마주할 때도 롤백이 필요하다면 반드시
@Transactional(rollbackFor = Exception.class)처럼 명시적으로 강제 속성을 지정해 주어야 합니다.
- A: 기본 속성상 Checked Exception은 롤백되지 않고 커밋해버립니다. 따라서 서비스 상 컴파일 예외를 마주할 때도 롤백이 필요하다면 반드시
Q. 트랜잭션 전파 속성(Propagation)에 대해 설명해주세요.
핵심 답변
이미 트랜잭션이 열려있는 외부 메서드에서 새로운 내부 트랜잭션 메서드를 연쇄 호출할 때, 그 내부 트랜잭션을 기존 것으로 묶을지 혹은 아예 별개의 선으로 분리할지 결정하는 정책입니다. 기본값인 REQUIRED는 기존 트랜잭션이 있으면 합류하고 없으면 새로 만듭니다. REQUIRES_NEW는 무조건 기존 통로를 잠시 멈추고 독립적인 새 트랜잭션을 개통하며, NESTED는 부모 트랜잭션 안에서 세이브포인트를 두는 종속 트랜잭션을 만듭니다.
꼬리 질문
- Q.
REQUIRES_NEW를 남발할 시 어떤 문제점이 발생할 수 있나요?- A: 하나의 HTTP 요청 로직에서 여러 개의 무관한 새 트랜잭션을 연쇄 발동시키므로, 한 프로세스가 동시에 여러 커넥션 풀(DB Connection) 자원을 점유하게 됩니다. 결국 커넥션 풀 고갈(Deadlock이나 Connection Timeout)로 이어져 사이트가 뻗어버릴 확률이 매우 큽니다.
Q. JPA 영속성 컨텍스트(Persistence Context)의 이점은?
핵심 답변
EntityManager가 논리적으로 DB와 어플리케이션 사이에 두는 가상의 중간 메모리 캐시망입니다.
- 1차 캐시: 한 번 조회한 엔티티를 기억해 동일 조회가 오면 DB를 거치지 않고 바로 반환합니다.
- 동일성 보장: 같은 식별자를 캐시에서 꺼내어
a == b의true객체 동일성을 보장합니다. - 트랜잭션을 지원하는 쓰기 지연: INSERT, UPDATE 쿼리를 날릴 때마다 DB에 쏘지 않고 지연 저장소에 모아두었다가 커밋 순간 네트워크에 한방에 쏟아보냅니다(Batch).
- 변경 감지(Dirty Checking): 엔티티의 필드만 수정해도 자동으로 업데이트 쿼리를 감지해 날려주며 5. 페치 전략에 맞춰 **지연 로딩(Lazy/Proxy)**을 제공합니다.
꼬리 질문
- Q. 1차 캐시가 있음에도 실무에서 극적인 조회 성능 향상을 보지 못하는 이유는?
- A: 1차 캐시는 무한정 유지되는 글로벌 캐시가 아니라, 클라이언트의 HTTP 단일 요청 한 번(트랜잭션 1개 주기) 동안만 살았다가 요청이 끝남과 동시에 영속성 덩어리가 통째로 폭파되기 때문에 찰나의 성능 이점밖에 누리지 못하기 때문입니다.
Q. JPA에서 N+1 문제는 무엇이며 어떻게 해결하나요?
핵심 답변
N+1 문제는 부모 엔티티 하나(1)를 DB에서 조회할 때, 연관된 자식 엔티티들을 채우기 위해 별도로 N번의 추가적인 SELECT 쿼리가 끔찍하게 불필요 폭발 현상으로 발생하는 현상입니다. Jpql에서 연관 편의(지연 로딩)로 접근할 때 주로 터집니다. 해결을 위해선 연관 엔티티를 한 방의 Join 쿼리로 다 긁어오는 **Fetch Join(페치 조인)**을 쓴명명하거나 @EntityGraph를 명시하며, 컬렉션의 경우 배치 사이즈(default_batch_fetch_size)를 걸어 IN 쿼리로 최적화 분할 해소합니다.
꼬리 질문
- Q. 컬렉션(OneToMany 등 자식 리스트)을
Fetch Join할 때 조심해야 할 페이징(Paging) 이슈는?- A: 다대일 조인은 문제가 없지만, 컬렉션을 Fetch Join 해버리면 데이터베이스 단에서 카테시안 결합으로 행이 N배 증식하기 때문에 JPA가 DB 차원에서의 최적 페이징(Limit, Offset) 덤프를 포기하고, 전체 N배 증식 데이터를 메모리(RAM)에 다 끌고온 뒤 애플리케이션 단에서 억지로 페이징을 시도해 메모리 초과 장애(Out of Memory)를 일으키는 치명적 제약이 발생합니다.
Q. 변경 감지(Dirty Checking)는 어떻게 동작하나요?
핵심 답변
JPA는 영속성 컨텍스트에 엔티티가 최초 저장되거나 조회될 때, 그 첫 인상의 원본 복사본 인스턴스를 메모리에 남겨두는데 이를 **스냅샷(Snapshot)**이라고 합니다. 이후 트랜잭션이 끝나는 커밋(Commit) 시점에 이 영속 상태의 엔티티들과 보유한 스냅샷 메모리를 일일이 대조하여, 데이터 필드에 단 1바이트라도 변경된 사항이 적발되면 스스로 UPDATE 쿼리문을 동적으로 생성해 쓰기 지연 저장소에 담아뒀다 커밋 전송하는 자동 갱신 기법입니다.
꼬리 질문
- Q. 변경 감지에 의해 생성되는 UPDATE 쿼리는 오직 변경된 컬럼만 반영하나요?
- A: 아닙니다. JPA는 기본 전략상 변경된 컬럼 뿐 아니라 해당 테이블의 모든 컬럼 값을 다 엎어치는 통짜 UPDATE 쿼리를 생성합니다. (그래야 앱 로딩 시점에 파싱된 쿼리를 재사용 캐싱할 수 있기 때문입니다). 만약 컬럼이 너무 거대해 변경된 부분만 동적으로 쏘고 싶다면 클래스 딴에
@DynamicUpdate를 붙여주어야 합니다.
- A: 아닙니다. JPA는 기본 전략상 변경된 컬럼 뿐 아니라 해당 테이블의 모든 컬럼 값을 다 엎어치는 통짜 UPDATE 쿼리를 생성합니다. (그래야 앱 로딩 시점에 파싱된 쿼리를 재사용 캐싱할 수 있기 때문입니다). 만약 컬럼이 너무 거대해 변경된 부분만 동적으로 쏘고 싶다면 클래스 딴에
Q. Entity와 DTO를 분리해야 하는 시스템적 이유는?
핵심 답변
가장 큰 이유는 도메인(테이블)의 오염과 프레젠테이션 로직의 침범 종속을 막기 위해서입니다.
DB 테이블과 1:1로 매핑되는 절대 핵상 핵심인 Entity를 프론트엔드 응답용으로 직통 노출하면, 화면에 보여주지 말아야 할 비밀번호 등의 민감 정보가 강제 누출됩니다. 이를 피하려고 Entity에 @JsonIgnore 같은 화면 기술 애노테이션을 도배하기 시작하면 핵심 계층과 화면 계층의 결합도가 파괴적으로 올라가 유지보수가 불가능해집니다. 따라서 화면 요구사항에 언제든 버려지고 맞춰지는 소모성 DTO(Data Transfer Object)를 필히 브릿지로 두어야 합니다.
꼬리 질문
- Q. DTO를 반환하더라도 Entity 자체를 DTO로 감싸서(Wrapping) 넘기는 것은 피해야 하나요?
- A: 절대 피해야 합니다. DTO 내부의 필드 멤버 변수로 Entity 객체가 쌩으로 들어가게 돌려준다면, 결국 클라이언트에서 그것을 열어보는 순간 Lazy Loading 프록시 지연 통신이 터지거나 JSON 렌더링을 위해 Entity의 전 정보를 다 뒤지게 되므로 Entity 강제 노출과 완벽히 다를 바 없는 참사가 발생합니다.
Q. @ControllerAdvice와 @ExceptionHandler를 이용한 예외 처리
핵심 답변
개별 컨트롤러 메서드 안에서 매번 try-catch로 에러를 잡는 지저분한 방식을 버리고, AOP 체제를 응용해 애플리케이션 전역(Global) 혹은 컨트롤러 계층 전반에서 발생한 에러를 낚아채서 중앙 집중식 대처를 하도록 만든 기능입니다.
전역 핸들러 클래스 위에 @ControllerAdvice를 정의해 두고, 그 안에 @ExceptionHandler(CustomException.class) 형태의 메서드를 박아두면 특정 예외 폭탄이 던져질 때마다 시스템이 터지지 않고 이쪽 가드 로직으로 넘어와 규격화된 에러 JSON 규격 응답을 안전하게 프론트로 넘길 수 있습니다.
꼬리 질문
- Q. 일반 @ControllerAdvice와 @RestControllerAdvice의 차이는 무엇인가요?
- A: 기능적인 체계는 같으나,
@RestControllerAdvice에는 내부적으로 컴포지트로 뷰를 반환하지 않고 JSON 응답을 몸체에 직접 박아 넘기는@ResponseBody메타 정보가 결합되어 있어 별도 템플릿 변환 우려 없이 깔끔하게 에러 JSON API 데이터를 분출합니다.
- A: 기능적인 체계는 같으나,
Q. CGLIB 프록시와 JDK 동적 프록시의 방식 차이는?
핵심 답변
스프링 AOP를 구현하는 두 가지 핵심 런타임 위임 생성기법입니다.
- JDK 동적 프록시(Dynamic Proxy): 무조건 타깃 클래스가 **'인터페이스(Interface)'**를 상속 구현하고 있어야만 프록시 생성이 가능하며, 기본 자바의 Reflection API를 돌려 프록시를 맵핑합니다.
- CGLIB: 인터페이스가 없어도 타깃 원본 클래스를 직접 **'상속(Extends)'**받아 프록시 자식 클래스를 강제로 낳아버리는 바이트코드 런타임 조작 기법입니다. (클래스가 final이거나 파라미터 없는 기본 생성자가 막혀있으면 상속 불가로 에러가 납니다)
꼬리 질문
- Q. 최신 버전의 Spring Boot는 주로 어느 방식을 채택하고 있나요?
- A: 과거에는 인터페이스 의존을 우선시해 JDK 프록시를 썼으나, 불필요한 인터페이스 강제 작성을 피하고 퍼포먼스(리플렉션 코스트 회피)가 더 입증된 CGLIB 방식을 스프링 부트 2.x 부터 기본(Default) AOP 생성 전략으로 강제 채택하여 구동하고 있습니다.
Q. 싱글톤 빈(Bean)은 스레드 세이프(Thread-Safe) 한가요?
핵심 답변
전혀 그렇지 않습니다. 스프링 컨테이너가 낳은 싱글톤 빈은 전체 웹 인스턴스에서 객체가 단 1개뿐입니다. 톰캣 스레드 풀에서 떨어져 나온 수십 수백 개의 동시 HTTP 요청 스레드들이 이 단 1개의 공용 싱글톤 빈에 마구잡이로 동시 접근하여 함수를 실행시킵니다. 따라서 빈 안에 **'상태를 유지하는 전역 멤버 필드 변수(Stateful Field)'**를 아무렇게나 선언하고 여러 스레드가 값을 덮어쓰고 읽게 구현하면 심각한 동시성 오염(Race Condition) 파멸이 일어납니다. 철저하게 값을 공유하지 않는 무상태(Stateless) 로직 구조로 짜야만 스레드 세이프를 이끌어낼 수 있습니다.
꼬리 질문
- Q. 멀티 스레드가 동시 접근할 때, 각각의 함수 내부 지역 변수들은 왜 중첩(오염)되지 않나요?
- A: 함수 선언문 안에서 구동되는 블록 지역 변수들이나 로컬 파라미터들은, 자바 메모리 영역 구조상 공유 힙(Heap)이 아니라 개별 접근 스레드들의 아주 사적이고 독립적인 JVM 메서드 호출 스택(Stack) 영역에 매번 새롭게 생겨나 격리 쌓이기 때문에 생명선이 꼬이는 일이 없습니다.
Q. Spring Container란 무엇인가요?
핵심 답변
스프링 빈(Bean)이라고 불리는 객체들의 구동부터 탄생과 소멸 과정을 프레임워크 차원에서 대신 쥐고(IoC) 의존관계를 투명하게 꽂아주는 관리 주체입니다. BeanFactory나 이를 확장한 ApplicationContext 인터페이스가 실질적인 컨테이너 역할을 하며 자바 객체를 중앙 통제 방식으로 싱글톤 체제에 맞춰 가꿔줍니다.
꼬리 질문
- Q. 빈(Bean)은 컨테이너 안에서 어떤 스코프(Scope)를 기본적으로 갖나요?
- A: 스프링 컨테이너는 기본적으로 빈을 싱글톤(Singleton) 환경 범위로 등록해 단 하나의 객체만 애플리케이션 내내 공용 인스턴스로 돌려 쓰는 메모리 최적화를 기본 무기로 탑재하고 있습니다.
Q. @SpringBootTest와 @WebMvcTest의 차이는?
핵심 답변
**@SpringBootTest**는 프로젝트에 등록된 스프링 모든 빈(수천 개)과 설정, 데이터베이스 스크립트 등을 전부 강제로 끌어올려 실제 구동과 똑같은 육중한 생태계를 띄우는 완전한 '통합 테스트(Integration Test)' 어노테이션입니다.
반면 **@WebMvcTest**는 Service 등 하위 레이어 빈은 모조리 무시해버리고, 오직 **웹 통신 프레젠테이션 계층(Controller, Interceptor, Security 등)**만 가볍게 올려 API 동작 호출만을 집중 분리 검증하는 '슬라이스 테스트(Slice Test)' 모델링으로 매우 신속한 검증이 가능한 도구입니다.
꼬리 질문
- Q. 그렇다면 @WebMvcTest 환경에서 내가 만든 비즈니스
Service나Repository빈 주입이 막히는데, 서비스가 포함된 테스트 흐름을 검증하려면 어떻게 해야 하나요?- A: 컨트롤러 테스트 시 서비스 레이어부터는 Mocking 체제로 대치하기 위해
@MockBean(또는 Mockito) 애노테이션을 사용하여 실제 동작하지 않는 깡통 로직 가짜 객체를 주입시켜 껍질 동작을 컨트롤 단위에 맞게 조작(Stubbing) 증명해야 합니다.
- A: 컨트롤러 테스트 시 서비스 레이어부터는 Mocking 체제로 대치하기 위해
Q. Bean의 생명주기를 설명해주세요.
핵심 답변
스프링 빈은 객체 생성 -> 의존관계 주입(DI) -> 초기화 콜백 호출 -> 애플리케이션 사용 단계 돌입 -> 컨테이너 종료 직전 소멸 콜백 호출 -> 최종 파기 소멸이라는 명확한 라이프사이클을 갖습니다. 생성자와 의존관계 주입이 완료되어야만 사용 가능한 제대로 된 객체라 판단하기 때문에 초기화 콜백 과정을 거칩니다.
꼬리 질문
- Q. 이러한 특정 콜백 단계를 가로채기 위해 개발자가 주로 사용하는 방식은?
- A: 자바 최신 표준인
@PostConstruct와@PreDestroy애노테이션을 메서드 상단에 붙여서, 초기화 혹은 소멸 직전의 알림 이벤트를 감지해 임의 코드 로직을 심는 방식이 가장 널리 쓰이고 추천됩니다.
- A: 자바 최신 표준인
Q. @Autowired는 어떻게 동작하나요?
핵심 답변
@Autowired 애노테이션을 부착하면 스프링 IoC 컴파일 컨테이너는 해당 타입과 호환되는 녀석(인스턴스 혹은 빈)을 자신이 관리하는 목록 내에서 뒤지어 매핑을 찾아, 런타임에 리플렉션(Reflection) 등의 원리를 활용해 주입 타깃에 대상 빈 의존성을 꽂아 버립니다.
꼬리 질문
- Q. 주입 가능한 빈이 두 개 이상 겹치면서 오류가 나면 어떻게 처리해야 하나요?
- A:
@Primary애노테이션을 타깃 특정 빈 구현체에 부착해 최우선권을 강제 명시 부여하거나, 호출단에서@Qualifier("특정Bean이름")를 지정해 둘 중 한 녀석을 지목 명명하면 명쾌하게 충돌이 정리됩니다.
- A:
Q. AOP란 무엇인가요?
핵심 답변
AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)는 어플리케이션 전체에 범용적으로 빈번히 공통 사용되는 트랜잭션, 권한 타당성, 보안 로깅 같은 '공통 관심사(Cross-Cutting Concern)' 로직을 별도로 분리해 모듈화하는 프로그래밍 패러다임입니다. 이를 மூலம் 비즈니스 핵심 로직(Core Concern)들의 코드 침범 오염을 막아 코드 직관성을 높입니다.
꼬리 질문
- Q. 스프링 AOP는 어떻게 이런 분리를 기술적으로 엮어 구현하나요?
- A: 스프링 컨테이너는 기본적으로 프록시(Proxy) 디자인 패턴을 적극 활용합니다. 원본 비즈니스 로직 클래스를 감싸는 가짜(대리인) 프록시 객체를 만들어, 메서드 호출 전 구간에 인터셉트하듯 어드바이스 로직을 실행하도록 기술적 트릭을 겁니다.
Q. Spring MVC 구조를 설명해주세요.
핵심 답변
사용자 클라이언트의 모든 요청이 들어오면 최전방 수문장 역할의 싱글 서블릿 DispatcherServlet이 전부 일단 접수한 후, 요청 경로 URL을 조회해 핸들러매핑에서 일치하는 처리를 해줄 Controller로 하달 지시를 내립니다. 컨트롤러에서 서비스와 연산이 끝나면 모델 어트리뷰트 데이터를 담은 ViewResolver에 전달하고, 징역이 완료된 HTML이나 최종 데이터 응답만을 유저에게 던져 넘기는 철저한 위임 기반 모델 아키텍처입니다.
꼬리 질문
- Q. REST API 구현이 중심인 근래에는 위 과정에서 어떤 모델이 많이 축소되거나 생략되나요?
- A:
@ResponseBody가 기본적으로 컨트롤러들에 무한 탑재되어서ViewResolver로직이 무의미해지고 대신HttpMessageConverter가 그 역할을 탈취해 자바 객체를 텍스트, 즉 JSON 혹은 XML 데이터 형태로 직접 변환 출력하는 식의 논스톱 덤프 위주로 흘러갑니다.
- A:
Q. DispatcherServlet의 역할은?
핵심 답변
스프링 MVC 내내 Front Controller 디자인 패턴 체제의 최전방 핵심 관문으로 활약합니다. 모든 빗발치는 HTTP 클라이언트 트래픽 요청을 단일 지점으로 빨아들여 접수한 뒤, 공통 처리 사항 등을 뺀 이후 URL 세부 루트에 따라 적합한 작업 분배와 위임 처리를 사방의 컨트롤러 및 리졸버 등으로 쏴주는 강력하고 묵직한 라우팅 중재 컨트롤 타워(지휘관) 역할을 전담 수행합니다.
꼬리 질문
- Q. Front Controller 패턴을 사용할 때의 이점은 무엇인가요?
- A: 보안과 인증, UTF-8 로깅(Encoding), 등 모든 컨트롤러가 중복해서 매번 수행해야 했던 각종 부차적인 공통 전처리 로직들을 단 한 번 Dispatcher 관문에서 싹 다 소화할 수 있어 압도적인 코드 재사용 효율을 제공합니다.
Q. @Controller와 @RestController 차이는?
핵심 답변
가장 큰 근본적 처리 차이는 반환 값의 용도입니다. @Controller는 주로 반환된 문자열 데이터를 바탕으로 ViewResolver에 전송해, 완성된 HTML 템플릿(뷰 화면, JSP/Thymeleaf)을 렌더링하고 조합해 반환하기 위해 목적으로 쓰입니다.
반면 @RestController는 내부에 @ResponseBody가 포함된 애노테이션으로 뷰 템플릿이 아닌 JSON, 텍스트 원형(Data) 포맷 그 자체를 HTTP 바디에 때려 직송하기 위한 API 전담 성격을 지닙니다.
꼬리 질문
- Q. 일반 @Controller에서 JSON 데이터를 보내려면 어떻게 해야 하나요?
- A: 원하는 전송 타깃 메서드(함수) 바로 위에 단순히
@ResponseBody를 붙이기만 하면 뷰 리졸버가 반응하지 않고 HttpMessageConverter가 발동해 객체를 JSON으로 직렬화해 화면 없이 넘겨줍니다.
- A: 원하는 전송 타깃 메서드(함수) 바로 위에 단순히
Q. Filter와 Interceptor 차이는?
핵심 답변
실행되는 위치 권역과 관리 주체가 다릅니다. 필터(Filter)는 톰캣 등 서블릿 컨테이너 웹 서버 앞단 구간에서 스프링 체제와 무관하게 모든 요청을 포괄 전역 필터링하는 전능한 역할(CORS, 로깅, 인코딩)을 맡습니다.
인터셉터(Interceptor)는 스프링의 DispatcherServlet까지 들어온 직후 실제 대상 컨트롤러를 매핑 호출하기 앞서 가로지르는 스프링 프레임워크 자체의 기능으로, 스프링 객체(빈) 인증, 권한 관리 등에 특화되어 동작합니다.
꼬리 질문
- Q. 예외 처리(Exception) 과정에서 두 가지 중 누가 더 스프링의
ControllerAdvice장점을 이용할 수 없나요?- A: 필터입니다. 필터 구역은 스프링의 생태계에 입성하기 전 컨테이너 소관이므로, 필터 구역 안에서 에러가 터졌을 때 전역
ControllerAdvice등 스프링식 우아한 Exception 예외 처리가 절대 불가한 기술적 절단 사각에 해당합니다.
- A: 필터입니다. 필터 구역은 스프링의 생태계에 입성하기 전 컨테이너 소관이므로, 필터 구역 안에서 에러가 터졌을 때 전역