신입 개발자 인터뷰 대비 - 7. Spring Framework
신입 개발자 인터뷰 대비 : 7. Spring Framework
네트워크 / 보안
Spring Framework에 대해 설명하시오, Spring Boot와 Spring의 차이점을 설명하시오
Spring Framework는 자바 플랫폼을 위한 강력하고 광범위하게 사용되는 개발 프레임워크다. 엔터프라이즈급 애플리케이션을 위해 다양한 기능을 제공하며, 특히 의존성 주입(Dependency Injection)과 관점 지향 프로그래밍(Aspect-Oriented Programming) 같은 개념을 적극적으로 활용하여 애플리케이션의 모듈성을 높이고, 개발을 단순화한다.
Spring Boot는 Spring 기반 애플리케이션을 빠르고 쉽게 개발할 수 있도록 도와주는 도구다. Spring Boot는 Spring의 복잡성을 크게 줄여주며, 스탠드얼론 애플리케이션을 쉽게 만들 수 있는 환경을 제공한다.
Spring과 Spring Boot의 차이점:
- 설정의 간소화:
- Spring: 전통적인 Spring 프레임워크는 설정이 매우 유연하지만 복잡할 수 있다. XML 설정이나 Java 기반 설정을 통해 빈을 수동으로 구성해야 한다.
- Spring Boot: 반면, Spring Boot는 자동 구성(auto-configuration)을 통해 많은 설정을 사전에 제공한다. 개발자는 애플리케이션의 비즈니스 로직에 더 집중할 수 있다.
- 내장 서버 사용:
- Spring: 전통적인 Spring 애플리케이션은 외부 서버에 배포해야 실행 가능하다.
- Spring Boot: Spring Boot는 내장 서버(Tomcat, Jetty 등)를 제공하여 애플리케이션을 쉽게 실행하고 테스트할 수 있다.
- 독립 실행 가능한 애플리케이션:
- Spring Boot: 애플리케이션을 ‘java -jar’ 명령어를 사용하여 실행할 수 있는 독립 실행형 패키지로 만들 수 있다.
- Spring: 일반적으로 WAR 파일을 생성하여 서버에 배포해야 한다.
- 의존성 관리:
- Spring Boot: ‘starter’ 의존성을 통해 필요한 라이브러리들을 간편하게 추가할 수 있다. 이 스타터 팩은 관련된 모든 의존성을 함께 제공한다.
- Spring: 개발자가 필요한 라이브러리의 의존성을 직접 관리해야 한다.
Spring Boot는 Spring의 기능을 모두 포함하면서, 개발 과정을 단순화하고 빠르게 프로토타이핑할 수 있게 도와준다. 따라서 개발 시간을 단축하고, 생산성을 높이는 데 크게 기여한다.
DI와 IoC, IoC Container(DI Container)에 대해 설명하시오.
의존성 주입(Dependency Injection, DI) 과 제어의 역전(Inversion of Control, IoC) 은 모듈화된 프로그래밍에서 중요한 개념이다. 이 두 용어는 종종 함께 사용되며, 특히 스프링 프레임워크와 같은 고급 프레임워크에서 주요한 역할을 한다.
제어의 역전(Inversion of Control, IoC)
- IoC 는 프로그램의 제어 흐름을 사용자가 직접 관리하는 대신, 외부 프레임워크나 라이브러리에 위임하는 디자인 패러다임이다. 이 개념의 핵심은 낮은 수준의 구성 요소가 자신의 로직 실행 방식을 직접 제어하지 않고, 고수준의 프레임워크에 그 책임을 넘긴다는 점이다.
- 예시: 애플리케이션에서 어떤 객체가 다른 객체의 인스턴스를 생성하고, 실행 순서를 결정하는 대신, 프레임워크가 이러한 작업을 관리하고 조정한다.
의존성 주입(Dependency Injection, DI)
- DI 는 IoC의 한 형태로, 객체가 필요로 하는 의존성(즉, 다른 객체나 서비스)을 직접 생성하는 대신 외부에서 받아 사용하는 기법이다. 이 방식은 객체간의 결합도를 낮추고, 유지보수 및 테스트의 용이성을 향상시킨다.
- 예시: 객체 A가 객체 B의 메서드를 사용해야 할 경우, A는 B의 인스턴스를 직접 생성하지 않고, 생성자나 세터를 통해 주입받는다.
IoC 컨테이너(DI 컨테이너)
- IoC 컨테이너 또는 DI 컨테이너 는 객체의 생성과 생명주기를 관리하고, 필요한 객체에 의존성을 자동으로 주입하는 역할을 한다. 이 컨테이너는 객체를 요청받으면 설정에 따라 객체를 생성하고, 의존성을 주입하여 반환한다.
- 구현: 스프링 프레임워크에서는
ApplicationContext
가 IoC 컨테이너의 역할을 수행한다. 이 컨테이너는 빈(bean)의 정의를 담고 있는 설정 정보를 바탕으로 빈 인스턴스를 생성, 관리, 제공한다.
IoC와 DI는 객체 지향 프로그래밍에서 중요한 원칙으로, 객체 간의 결합도를 낮추어 유연성을 높이고, 코드 재사용을 용이하게 하며, 코드 관리를 보다 효율적으로 만든다.
POJO가 무엇인지에 대해 설명하시오
POJO(Plain Old Java Object) 는 “순수한 오래된 자바 객체”라는 의미로, 자바 언어의 기본 문법에만 의존하며, 특정 규약이나 환경에 종속되지 않는 단순한 자바 객체를 말한다. POJO 개념은 JavaBeans, EJB(Enterprise JavaBeans) 등과 같이 특정 기술에 의존적인 객체와 대조적으로 사용된다.
POJO의 주요 특징은 다음과 같다:
- 특정 기술에 의존하지 않는 구조:
- POJO는 특정 프레임워크나 컨테이너 환경을 필요로 하지 않는다. 예를 들어, 서블릿 API나 EJB 인터페이스를 구현하거나 확장할 필요가 없다.
- 객체지향 원칙에 충실:
- POJO는 자바의 객체지향적 특성을 그대로 활용할 수 있어, 상속, 인터페이스, 다형성 등의 기능을 자유롭게 사용할 수 있다.
- 재사용성 및 테스트 용이성:
- 특정 인프라스트럭처에 종속되지 않기 때문에, POJO는 재사용이 용이하고 단위 테스트하기도 편리하다.
- 간결성:
- POJO는 비즈니스 로직에 집중할 수 있도록 간단하게 작성된다. 복잡한 구성 요소나 설정 없이도 충분히 기능을 수행할 수 있다.
POJO의 도입은 자바 개발을 더욱 단순화시키고, 개발자가 기술적 복잡성보다는 비즈니스 로직에 더 집중할 수 있게 도와준다. 스프링 프레임워크 같은 현대적인 개발 프레임워크는 POJO를 기반으로 하여 유연성과 확장성을 제공한다. 이를 통해 개발자는 보다 효과적으로 애플리케이션을 구축할 수 있다.
SpringMVC에 대해 설명하고, MVC가 어떤 흐름으로 요청을 처리하는지 설명하시오
Spring MVC는 Spring Framework의 일부로, 웹 애플리케이션을 개발하기 위한 모델-뷰-컨트롤러(MVC) 아키텍처를 제공하는 모듈이다. Spring MVC는 풍부한 구성 요소와 함께 유연하고 확장 가능한 방식으로 웹 애플리케이션을 구축할 수 있게 도와준다.
Spring MVC의 주요 구성 요소:
- 모델(Model): 데이터와 비즈니스 로직을 포함하며, 상태 정보와 데이터를 처리하는 역할을 한다.
- 뷰(View): 사용자 인터페이스를 담당하며, 모델이 처리한 데이터를 사용자에게 보여주는 방식을 정의한다.
- 컨트롤러(Controller): HTTP 요청을 받아 처리하는 컴포넌트로, 모델을 조작하고 그 결과를 뷰에 전달한다.
MVC 요청 처리 흐름:
- 클라이언트 요청 수신:
- 사용자의 요청은 먼저 DispatcherServlet에 의해 받아진다. DispatcherServlet은 Spring MVC의 프론트 컨트롤러로 모든 요청을 중앙에서 관리한다.
- 핸들러 매핑(Handler Mapping):
- DispatcherServlet은 요청을 분석하고 해당 요청을 처리할 적절한 컨트롤러를 찾기 위해 HandlerMapping 객체를 사용한다.
- 컨트롤러 실행:
- 적절한 컨트롤러가 결정되면, DispatcherServlet은 해당 컨트롤러의 메서드를 호출한다. 컨트롤러는 요청을 처리하고, 결과 데이터를 모델에 저장하며, 응답을 위한 뷰 이름을 반환한다.
- 뷰 리졸버(View Resolver):
- 컨트롤러가 반환한 뷰 이름을 받은 후, DispatcherServlet은 ViewResolver를 사용하여 이 이름을 실제 뷰 객체로 변환한다. 이 과정을 통해 요청에 대한 응답으로 무엇을 보여줄지 결정된다.
- 뷰 렌더링:
- 뷰 객체는 모델 데이터를 사용하여 최종적인 사용자 인터페이스를 생성한다. 이 인터페이스는 HTML 형태로 사용자에게 보여지며, 이 과정에서 JavaScript, CSS 등이 포함될 수 있다.
- 응답 반환:
- 렌더링된 뷰가 최종적으로 사용자의 브라우저에 반환된다.
Spring MVC는 이와 같은 명확한 역할 분리와 효율적인 요청 처리 흐름 덕분에 개발자가 웹 애플리케이션을 보다 쉽고 효과적으로 구현할 수 있도록 돕는다. 각 구성 요소가 잘 정의된 책임을 가지며, 이는 유지보수와 확장성에도 큰 장점을 제공한다.
Spring Bean과 Bean을 등록하는 방법을 설명하고, 라이프 사이클이 어떻게 관리되는지 설명하시오
Spring Bean은 Spring IoC 컨테이너가 관리하는 객체다. 이 객체들은 애플리케이션의 핵심을 이루며, 의존성 주입을 통해 관리된다. Bean을 등록하는 주요 방법은 세 가지다.
- XML 파일 사용:
beans.xml
과 같은 XML 설정 파일에<bean>
태그를 사용해 클래스 경로와 Bean의 속성을 정의한다. - 어노테이션 사용:
@Component
,@Service
,@Repository
,@Controller
등의 어노테이션을 클래스에 적용해 자동으로 Bean을 등록한다.@Configuration
어노테이션과@Bean
어노테이션을 함께 사용하면 메소드 레벨에서 수동으로 Bean을 정의할 수 있다. - Java Config 클래스 사용:
@Configuration
어노테이션이 적용된 클래스 내에서@Bean
어노테이션을 메소드에 붙여 Bean을 직접 등록할 수 있다.
Spring Bean의 라이프 사이클 관리는 다음 단계로 진행된다.
- 인스턴스화: 지정된 Bean 클래스의 인스턴스가 생성된다.
- 속성 설정: Bean에 주입할 속성이나 의존성이 설정된다.
- Bean 이름 인식: Bean의 이름이 컨테이너에 등록된다.
- BeanFactoryAware 및 BeanNameAware: Bean이
BeanNameAware
및BeanFactoryAware
를 구현한 경우,setBeanName
과setBeanFactory
메소드가 호출된다. - InitializingBean 및 init-method: Bean이
InitializingBean
을 구현한 경우afterPropertiesSet
메소드가 실행되며, 사용자가 정의한 초기화 메소드(init-method
)가 호출된다. - Bean 사용: Bean이 완전히 생성되어 사용할 준비가 완료되면, 애플리케이션에서 해당 Bean을 사용할 수 있다.
- DisposableBean 및 destroy-method: 컨테이너가 종료되면,
DisposableBean
의destroy
메소드와 사용자 정의destroy-method
가 호출되어 Bean이 제대로 종료되도록 한다.
이렇게 Spring의 Bean 등록과 라이프 사이클 관리는 유연하면서도 체계적으로 이루어져 애플리케이션의 효율성과 유지보수성을 높인다.
AOP, PSA가 무엇인지 설명하시오
AOP(Aspect-Oriented Programming)와 PSA(Portable Service Abstraction)는 Spring 프레임워크에서 중요한 개념이다. 이 두 개념은 애플리케이션의 설계와 유지보수성을 향상시키는 데 도움을 준다.
-
AOP(Aspect-Oriented Programming): 관점 지향 프로그래밍은 횡단 관심사(Cross-cutting Concerns)를 모듈화하는 프로그래밍 패러다임이다. 이는 로깅, 보안, 트랜잭션 관리 등과 같은 기능을 애플리케이션의 여러 부분에 걸쳐 공통적으로 사용하는 기능을 별도의 모듈(Aspect)로 분리하여 관리할 수 있게 해준다. AOP는
@Aspect
어노테이션을 사용하여 Aspect를 정의하고, 포인트컷(Pointcut)을 사용해 어떤 메소드가 Aspect의 영향을 받을지 결정하며, 어드바이스(Advice)는 실제로 실행할 로직을 정의한다. -
PSA(Portable Service Abstraction): 휴대 가능한 서비스 추상화는 하위 기술의 구체적인 구현 세부 사항으로부터 개발자를 보호하는 Spring의 설계 철학이다. 이는 같은 서비스를 다른 환경에서도 일관된 방식으로 사용할 수 있도록 지원한다. 예를 들어, Spring의 템플릿/콜백 패턴은 JDBC, JMS, JPA 등 여러 데이터 액세스 기술에 대해 일관된 프로그래밍 모델을 제공한다. 또한, Spring MVC는 웹 계층에 대한 추상화를 제공하며, 개발자는 특정 서버 구현 세부 사항을 신경 쓰지 않고도 웹 애플리케이션을 개발할 수 있다.
AOP와 PSA는 모두 소프트웨어의 모듈성을 향상시키고, 유지보수를 용이하게 하며, 개발자가 비즈니스 로직에 더 집중할 수 있도록 도와준다. 이러한 기능은 Spring이 제공하는 강력한 도구들 중 일부로, 애플리케이션 전반에 걸쳐 일관된 아키텍처를 유지하도록 지원한다.
DAO, DTO, VO, BO가 무엇인지 설명하시오
DAO, DTO, VO, BO는 소프트웨어 개발, 특히 자바 기반 애플리케이션에서 자주 사용되는 패턴 및 객체들이다. 이들은 데이터 처리와 비즈니스 로직을 효율적으로 관리하기 위해 설계되었다.
-
DAO (Data Access Object): 데이터 액세스 객체는 데이터베이스와의 상호작용을 처리하는 클래스다. 이 객체는 데이터베이스에 대한 모든 CRUD(Create, Read, Update, Delete) 연산을 캡슐화하여, 데이터베이스 쿼리와 같은 데이터 액세스 로직을 비즈니스 로직으로부터 분리한다. 이로 인해 애플리케이션의 유지보수성이 향상되고 데이터 액세스 메커니즘이 변경되어도 비즈니스 로직에 영향을 미치지 않는다.
-
DTO (Data Transfer Object): 데이터 전송 객체는 계층 간 데이터 교환을 위해 사용된다. 특히 네트워크를 통한 데이터 전송이나 API 응답에서 복잡한 데이터 구조를 간단하게 전달할 때 사용된다. DTO는 로직을 포함하지 않고 순수하게 데이터를 전달하는 데에 초점을 맞춘 객체다.
-
VO (Value Object): 값 객체는 DTO와 유사하게 데이터를 포함하지만, 불변성을 가지는 경우가 많다. VO는 주로 데이터의 표현을 목적으로 사용되며, 동일한 데이터를 가지면 같은 해시코드와 동등성을 가진다는 특징을 가진다. VO는 데이터를 하나의 논리적 단위로 표현하기 위해 사용된다.
-
BO (Business Object): 비즈니스 객체는 비즈니스 로직을 캡슐화하는데 사용된다. 이 객체는 데이터의 처리와 관련된 규칙이나 계산 등 비즈니스에 필요한 연산을 수행한다. BO는 일반적으로 DAO를 사용하여 데이터를 처리하고, 결과를 DTO나 VO를 통해 전달한다.
이들 객체는 각각의 역할과 책임에 따라 소프트웨어의 구조를 체계적으로 만들어, 유지보수와 확장이 용이하게 한다. 데이터의 흐름과 처리 방식을 명확히 하여 개발 과정에서의 혼란을 최소화하고, 애플리케이션의 안정성과 성능을 향상시키는 데 기여한다.
JPA가 무엇인지 설명하고, 언제 사용해야 좋을 지를 설명하시오
JPA(Java Persistence API)는 자바 어플리케이션에서 관계형 데이터베이스의 데이터를 관리(영속성 관리)하는 표준 API다. 이는 자바 객체와 데이터베이스 테이블 간의 매핑을 쉽게 하여, 개발자가 데이터베이스 연산을 보다 직관적으로 처리할 수 있게 도와준다. JPA는 데이터베이스와의 상호작용을 추상화하고, 직접적인 SQL 코딩 없이 데이터를 조작할 수 있게 한다.
JPA의 주요 특징
- ORM (Object-Relational Mapping): 객체 지향 모델과 관계형 데이터베이스 모델 간의 브리지 역할을 하며, 객체를 데이터베이스 테이블에 자동으로 매핑한다.
- 데이터베이스 독립성: JPA를 사용하면 특정 데이터베이스 SQL에 의존하지 않고, 다양한 데이터베이스 제품에 대해 동일한 데이터 액세스 코드를 사용할 수 있다.
- 쉬운 데이터 접근 및 코딩: 엔티티 매니저를 통해 CRUD 연산을 간단하게 수행할 수 있고, 복잡한 조인, 검색, 저장 절차를 간소화한다.
- 트랜잭션 관리 및 지연 로딩: 트랜잭션 기반의 쿼리 실행과 필요할 때까지 데이터를 로딩하는 지연 로딩을 지원한다.
JPA 사용이 적합한 경우
- 도메인 중심 설계를 구현할 때: 도메인 모델이 복잡하고, 데이터베이스 연산을 객체 지향적으로 관리하고 싶을 때 JPA 사용이 이점을 제공한다.
- 데이터베이스 독립적인 어플리케이션 개발이 필요할 때: 다양한 데이터베이스에 대응해야 하고, 데이터베이스 교체 가능성이 있을 때 JPA는 코드 변경 없이 데이터베이스 교체를 용이하게 한다.
- CRUD 연산의 간소화가 필요할 때: 반복적인 CRUD 코드를 줄이고, 표준화된 API를 통해 개발 생산성을 높이고 싶을 때 JPA는 큰 도움이 된다.
- 대규모 데이터 처리가 필요할 때: 캐싱, 배치 처리, 페이징과 같은 기능을 제공하여 대량의 데이터 처리에 효율적이다.
JPA는 개발자가 SQL에 신경 쓰지 않고 비즈니스 로직 개발에 더 집중할 수 있게 해주며, 데이터 액세스 계층을 보다 견고하고 유지보수하기 쉽게 만들어 준다. 그러나 JPA의 학습 곡선과 성능 최적화가 필요한 경우도 있기 때문에 프로젝트의 요구 사항과 팀의 기술 수준을 고려하여 도입을 결정해야 한다.
Servlet이 무엇인지, 동작방식은 어떻게 되는지 설명하시오.
Servlet은 자바 기반 웹 애플리케이션을 개발하기 위한 서버 사이드 컴포넌트로, HTTP 요청을 처리하고 응답을 생성하는 역할을 수행한다. Servlet API는 자바 EE(Enterprise Edition)의 일부로 제공되며, 웹 서버나 애플리케이션 서버에서 실행된다.
Servlet의 주요 기능
- HTTP 요청 수신: 클라이언트(웹 브라우저나 다른 서버)으로부터 HTTP 요청을 받아들인다.
- 비즈니스 로직 처리: 요청에 따른 처리를 수행한다. 이는 데이터베이스와의 상호작용, 계산 수행 등을 포함할 수 있다.
- HTTP 응답 생성: 처리 결과를 바탕으로 HTML, JSON 등의 형태로 응답을 생성하고 클라이언트에 전송한다.
Servlet의 동작 방식
- 요청 수신: 클라이언트로부터 HTTP 요청이 들어오면, 웹 서버는 이 요청을 Servlet 컨테이너에 전달한다.
- Servlet 로딩: 요청을 받은 Servlet이 메모리에 아직 로드되지 않았다면, Servlet 컨테이너는 해당 Servlet 클래스를 메모리에 로드한다.
- 인스턴스 생성: Servlet 클래스의 인스턴스가 생성된다. 각 Servlet에 대해 일반적으로 단일 인스턴스만 생성되며, 여러 요청에 대해 멀티스레드로 처리될 수 있다.
- 초기화:
init
메소드가 호출되어 Servlet이 초기화된다. 이 단계에서 필요한 자원을 할당받거나 구성 정보를 읽는 등의 작업이 수행된다. - 요청 처리:
service
메소드가 호출되며, 이 메소드 내에서는 HTTP 요청의 종류(GET, POST 등)에 따라doGet
,doPost
등의 메소드가 다시 호출된다. 이 메소드들은 실제 요청 처리 로직을 구현한다. - 응답 반환: 처리 결과를 HTTP 응답으로 클라이언트에 전송한다.
- 종료: 요청 처리가 완료되면, Servlet은 필요한 경우 자원을 정리하고, 서버가 종료되거나 Servlet이 필요 없어질 때
destroy
메소드가 호출되어 마지막 정리 작업을 수행한다.
Servlet은 웹 애플리케이션에서 서버측 로직을 구현하는 데 사용되며, 간단한 웹 애플리케이션부터 복잡한 엔터프라이즈 애플리케이션까지 다양하게 활용될 수 있다. 특히, 동적인 웹 컨텐츠를 생성하고 클라이언트와의 상호작용이 필요한 경우에 중요한 역할을 한다.
Spring에서 트랜잭션을 적용하는 방식에 대해 설명하시오
Spring 프레임워크에서 트랜잭션을 적용하는 방식은 주로 선언적 트랜잭션 관리와 프로그래매틱 트랜잭션 관리 두 가지 방법으로 나눌 수 있다. 이 중 선언적 트랜잭션 관리가 더 널리 사용되며, Spring의 트랜잭션 추상화는 개발자가 하위 데이터베이스 기술과 독립적으로 트랜잭션을 관리할 수 있게 해준다.
선언적 트랜잭션 관리
선언적 트랜잭션 관리는 주로 어노테이션 또는 XML 기반의 설정을 사용하여 적용된다. 가장 일반적인 방법은 @Transactional
어노테이션을 사용하는 것이다.
- @Transactional 어노테이션: 메소드나 클래스에
@Transactional
어노테이션을 추가함으로써 해당 범위의 메소드가 트랜잭션의 범위 안에서 실행되도록 한다. 이 어노테이션은 다양한 속성을 제공하여 트랜잭션의 동작을 세밀하게 제어할 수 있다. 예를 들어,propagation
,isolation
,timeout
,readOnly
,rollbackFor
,noRollbackFor
등의 속성을 설정할 수 있다.propagation
: 트랜잭션 전파 행위를 정의한다. 예를 들어, 이미 진행 중인 트랜잭션이 있을 때 이를 재사용할지 새로운 트랜잭션을 시작할지 결정한다.isolation
: 트랜잭션 격리 수준을 설정하여 동시에 여러 트랜잭션이 실행될 때 서로 영향을 주지 않도록 한다.timeout
: 트랜잭션의 최대 실행 시간을 지정한다.readOnly
: 트랜잭션을 읽기 전용으로 설정한다.
프로그래매틱 트랜잭션 관리
프로그래매틱 트랜잭션 관리는 TransactionTemplate
또는 PlatformTransactionManager
를 직접 사용하여 트랜잭션의 시작, 종료 및 롤백을 코드 내에서 직접 제어한다. 이 방법은 더 복잡하지만, 트랜잭션 관리를 더 유연하게 제어할 수 있는 장점이 있다.
- TransactionTemplate:
TransactionTemplate
를 사용하여 트랜잭션 경계를 설정하고, 실행할 코드를TransactionCallback
인터페이스의 구현을 통해 전달한다.TransactionTemplate
는 코드 내에서 트랜잭션 로직을 명확하게 분리할 수 있도록 해준다. - PlatformTransactionManager:
PlatformTransactionManager
인터페이스를 통해 트랜잭션을 직접 관리할 수 있다. 이는 트랜잭션을 시작, 커밋, 롤백하는 메소드를 제공하여, 코드 내에서 직접 트랜잭션의 생명 주기를 제어할 수 있게 해준다.
사용 적합성
선언적 트랜잭션 관리는 대부분의 경우에 적합하며, 코드의 가독성과 유지보수성을 높여준다. 반면, 복잡한 트랜잭션 관리가 필요하거나, 트랜잭션 처리를 프로그래밍 방식으로 세밀하게 제어해야 하는 경우 프로그래매틱 트랜잭션 관리를 사용할 수 있다.
Autowiring 과정에 대해 설명하시오.
Spring 프레임워크에서 Autowiring은 의존성 주입(Dependency Injection)을 자동으로 처리하는 과정을 말한다. 이는 개발자가 수동으로 각 컴포넌트의 의존성을 연결할 필요 없이, Spring 컨테이너가 애플리케이션 컨텍스트 내에서 선언된 Bean들 사이의 의존성을 자동으로 연결해주는 기능이다.
Autowiring의 주요 방법
Spring에서는 주로 세 가지 방법으로 Autowiring을 할 수 있다:
- @Autowired 어노테이션: 가장 일반적인 방법으로, 필드, 생성자, 세터 메소드에 @Autowired 어노테이션을 사용한다. Spring 컨테이너는 이 어노테이션이 붙은 곳에 자동으로 해당 타입과 일치하는 Bean을 찾아 주입한다.
- @Resource 어노테이션: @Resource 어노테이션은 이름 기반으로 의존성을 주입한다. 주로 이름을 명시하여 정확한 Bean을 지정할 때 사용된다.
- @Inject 어노테이션: Java의 표준 의존성 주입 어노테이션으로, @Autowired와 유사하지만, 선택적인 의존성과 함께 사용할 수 없는 차이점이 있다.
Autowiring 과정
Autowiring 과정은 다음과 같이 진행된다:
- Bean 정의 스캔: Spring 컨테이너는 구성 클래스나 XML 파일, 어노테이션 등을 통해 Bean 정의를 로드하고 스캔한다.
- 의존성 해석: 컨테이너는 @Autowired 또는 다른 Autowiring 어노테이션이 적용된 필드, 세터, 생성자를 찾는다.
- 타입 매칭: Autowiring은 주로 타입 기반으로 이루어진다. 컨테이너는 요구되는 타입과 호환되는 Bean을 애플리케이션 컨텍스트 내에서 찾는다.
- 의존성 주입: 호환되는 Bean을 찾으면, 해당 Bean의 인스턴스가 자동으로 필요한 위치에 주입된다.
- 예외 처리: 적절한 Bean을 찾지 못하거나, 여러 개의 Bean이 존재하여 모호한 경우에는 예외가 발생한다. 이때,
@Qualifier
어노테이션을 사용하여 주입할 정확한 Bean을 명시할 수 있다.
Autowiring은 코드를 더 깔끔하고 관리하기 쉽게 만들며, 개발자가 의존성 관리에 드는 수고를 크게 줄여준다. 하지만, 사용 시 Bean 간의 의존성이 명확히 보여야 하고, 애플리케이션의 규모가 커질수록 더 세심한 관리가 필요할 수 있다.
Spring Web MVC의 Dispatcher Servlet 의 동작 원리에 대해서 간단히 설명하시오.
Spring Web MVC 프레임워크의 핵심 구성 요소인 Dispatcher Servlet은 웹 애플리케이션에서 HTTP 요청을 중앙에서 조정하고 관리하는 프론트 컨트롤러 역할을 수행한다. 이는 모든 요청을 받아 적절한 처리기(Controller)에게 전달하고, 그 결과를 클라이언트에게 반환하는 중심적인 역할을 한다.
Dispatcher Servlet의 동작 원리는 다음과 같은 단계로 이루어진다:
- 요청 수신: Dispatcher Servlet은 서버로 들어오는 모든 요청을 받는다. 일반적으로 URL 패턴(
/*
또는/.do
등)을 통해 이 Servlet이 구성된다. - Handler Mapping 조회: 요청을 처리할 수 있는 Controller를 찾기 위해 Dispatcher Servlet은 Handler Mapping을 조회한다. Handler Mapping은 URL과 Controller 사이의 매핑 정보를 가지고 있다.
- Controller 실행: 적절한 Controller가 결정되면, Dispatcher Servlet은 해당 Controller의 메소드를 호출하여 요청을 처리하도록 한다.
- ModelAndView 반환: Controller는 로직을 처리한 후, 결과 데이터와 결과 뷰에 대한 정보를 담은 ModelAndView 객체를 Dispatcher Servlet에 반환한다.
- View Resolver: ModelAndView 객체에 지정된 뷰 이름을 바탕으로 View Resolver가 실제 뷰 객체를 찾아낸다. View Resolver는 뷰 이름을 기반으로 뷰 템플릿 파일의 위치를 결정한다.
- 뷰 렌더링: 뷰 객체는 모델 데이터를 사용하여 최종 사용자에게 보여줄 HTML을 생성한다. 이 과정에서 JSP, Thymeleaf 등 다양한 뷰 템플릿 엔진이 사용될 수 있다.
- 응답 반환: 렌더링된 뷰가 최종적으로 클라이언트에게 응답으로 반환된다.
이 과정을 통해 Dispatcher Servlet은 MVC 패턴의 구현을 중앙에서 조정하여, 개발자가 각 부분을 명확히 분리하고 관리할 수 있게 해준다. 이로 인해 애플리케이션의 유지보수성과 확장성이 향상되며, 다양한 웹 개발 요구를 효과적으로 충족할 수 있다.
프론트 컨트롤러 패턴이란 무엇인가?
프론트 컨트롤러 패턴은 웹 애플리케이션 아키텍처에서 널리 사용되는 디자인 패턴 중 하나로, 모든 클라이언트 요청을 단일 진입점을 통해 처리하는 구조를 말한다. 이 패턴의 핵심은 모든 요청을 처음에 하나의 컨트롤러가 받아들여 적절한 처리기(handler)로 요청을 전달하는 것이다. 이를 통해 애플리케이션의 요청 처리 과정을 중앙에서 관리할 수 있으며, 다양한 요청에 대한 일관된 처리 로직을 제공할 수 있다.
프론트 컨트롤러 패턴의 주요 특징
- 단일 진입점: 모든 요청은 동일한 진입점을 통해 처리되므로 보안, 로깅, 서비스 품질 관리 등의 공통 로직을 쉽게 적용할 수 있다.
- 요청 관리의 중앙화: 요청에 대한 공통 처리 로직을 한 곳에서 관리함으로써 코드의 중복을 줄이고, 유지보수를 간편하게 할 수 있다.
- 구성의 유연성: 새로운 요청 처리기를 추가하거나 기존의 처리 로직을 변경할 때 프론트 컨트롤러 코드를 수정하지 않고도 확장성 있게 관리할 수 있다.
프론트 컨트롤러 패턴의 구현 예
- 웹 프레임워크에서의 구현: Java의 Spring MVC에서 Dispatcher Servlet이 프론트 컨트롤러 역할을 한다. 이는 모든 웹 요청을 처음에 받아들이고 적절한 컨트롤러로 요청을 전달한다.
- 서비스 지향 아키텍처: 대규모 시스템에서 프론트 컨트롤러는 API 게이트웨이나 서비스 라우터 역할을 수행하여, 다양한 백엔드 서비스로 요청을 효과적으로 분배한다.
프론트 컨트롤러 패턴은 웹 애플리케이션의 구조를 명확하게 정의하고, 공통 기능을 효율적으로 처리할 수 있는 강력한 방법을 제공한다. 따라서 이 패턴은 복잡하고 규모가 큰 웹 애플리케이션 또는 서비스를 개발할 때 특히 유용하다.
Serverlet Filter 와 Spring Interceptor 의 차이는 무엇인가?
Servlet Filter와 Spring Interceptor는 웹 애플리케이션에서 요청 및 응답을 가로채는 중간처리기로 작동하며, 각각의 컴포넌트는 유사한 역할을 하지만 다른 목적과 구현 상세, 실행 단계에서 차이가 있다.
Servlet Filter
- 정의: Servlet Filter는 Java EE 사양의 일부로, 모든 종류의 요청(서블릿 요청, 정적 파일 요청, JSP 페이지 요청 등)에 대해 동작한다. 이 필터는 요청과 응답을 가공, 변경, 조사하는 다양한 목적으로 사용된다.
- 목적: 보안 검사, 요청 로깅, 인코딩 설정, 권한 검사 등과 같이 요청 및 응답에 대한 전처리 및 후처리를 수행한다.
- 적용 범위: 필터는 웹 애플리케이션에 정의된 순서대로 실행되며, Dispatcher Servlet에 도달하기 전과 후에 실행될 수 있다.
- 동작 단계: 필터 체인을 통해 여러 필터가 순차적으로 요청 및 응답을 처리하고, 체인의 다음 필터 또는 실제 리소스로 요청을 전달하거나, 요청 처리를 중단할 수 있다.
Spring Interceptor
- 정의: Spring Framework의 일부로, Dispatcher Servlet과 컨트롤러 사이의 특정 지점에서 요청을 가로채는 역할을 한다. 주로 Spring MVC 컨트롤러의 실행 과정에서 동작한다.
- 목적: 주로 컨트롤러의 실행 전후로 데이터를 조작하거나 추가 로직을 수행하기 위해 사용된다. 예를 들어, 실행 시간 로깅, 권한 검사, 사용자 세션 검증 등이 이에 해당한다.
- 적용 범위: Spring MVC의 컨트롤러를 통해 처리되는 요청에만 적용되며, 정적 리소스 요청에는 적용되지 않는다.
- 동작 단계: Interceptor는 컨트롤러 호출 전(preHandle), 컨트롤러 실행 후(postHandle), 그리고 응답이 완전히 렌더링된 후(afterCompletion)의 세 가지 주요 지점에서 실행될 수 있다.
차이점 요약
- 적용 범위: Servlet Filter는 애플리케이션의 모든 요청에 대해 동작할 수 있는 반면, Spring Interceptor는 Spring MVC의 컨트롤러를 통해 처리되는 요청에만 적용된다.
- 구현 상세: Servlet Filter는 서블릿 API의 일부이며, Spring Interceptor는 Spring Framework의 일부로, Spring의 기능과 밀접하게 통합된다.
- 동작 시점: Filter는 요청 및 응답이 Dispatcher Servlet에 도달하기 전과 후에 실행될 수 있지만, Interceptor는 Dispatcher Servlet을 통해 처리된 후, 컨트롤러가 호출되기 전후에 동작한다.
이러한 차이점을 고려하여 애플리케이션의 필요에 따라 적절한 도구를 선택할 수 있다.
Spring 에서 CORS 에러를 해결할 수 있는 방법을 설명하시오
Spring에서 CORS(Cross-Origin Resource Sharing) 에러를 해결하기 위해 사용할 수 있는 방법은 여러 가지가 있다. 주로 사용되는 방법은 다음과 같다:
- Global Configuration 사용:
WebMvcConfigurer
인터페이스를 구현한 설정 클래스를 통해 전역 CORS 정책을 설정할 수 있다. 이 방식은 모든 컨트롤러에 대해 일관된 CORS 정책을 적용할 때 유용하다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true);
}
}
- Controller별 설정: 특정 컨트롤러 또는 요청 핸들러에
@CrossOrigin
어노테이션을 사용하여 CORS 정책을 설정할 수 있다. 이 방법은 특정 API에 대해서만 다른 CORS 정책을 적용하고 싶을 때 유용하다.
@RestController
@RequestMapping("/api")
public class ApiController {
@CrossOrigin(origins = "http://example.com")
@GetMapping("/example")
public String example() {
return "Example";
}
}
- Filter 사용:
CorsFilter
를 사용하여 더 세밀한 CORS 설정을 적용할 수 있다. 이는 Spring Security와 같은 보안 설정과 통합되어 사용될 수 있으며, 필터를 통해 HTTP 요청에 대한 CORS 처리를 직접 관리할 수 있다.
@Bean
public FilterRegistrationBean<CorsFilter> customCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://example.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
이 방법들을 통해 다양한 상황에서 CORS 에러를 해결할 수 있으며, 각 프로젝트의 요구사항에 맞추어 적절한 방법을 선택하면 된다.
Bean/Component 어노테이션에 대해 설명하고, 둘의 차이점을 설명하시오.
Spring Framework에서 @Bean
과 @Component
어노테이션은 모두 스프링 컨테이너에 빈(bean)을 등록하는 데 사용된다. 그러나 사용 방법과 목적에 차이가 있다.
@Bean
- 용도:
@Bean
어노테이션은 메소드에 사용되며, 이 메소드가 반환하는 객체를 스프링 컨테이너에 빈으로 등록한다. 주로@Configuration
어노테이션이 붙은 클래스 내부에 위치한다. - 적용 위치: 메소드 레벨에서 사용되며, 반환된 객체는 스프링 컨테이너가 관리하는 빈이 된다.
- 사용 사례: 외부 라이브러리 또는 복잡한 생성 과정을 거쳐야 하는 객체를 스프링 빈으로 등록할 때 사용한다.
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@Component
- 용도:
@Component
어노테이션은 클래스 레벨에서 사용되며, 해당 클래스의 인스턴스를 스프링 컨테이너에 빈으로 자동으로 등록하게 한다. 이는 컴포넌트 스캔(component scan)을 통해 자동으로 이루어진다. - 적용 위치: 클래스 레벨에서 사용되며, 보통 서비스, 리포지토리, 컨트롤러 등의 구성 요소에 사용된다.
- 사용 사례: 개발자가 직접 작성한 클래스를 스프링 빈으로 등록할 때 주로 사용한다.
@Component
public class MyComponent {
// 클래스 코드
}
차이점
- 적용 범위:
@Bean
은 메소드에 적용되어 메소드가 생성하는 객체를 빈으로 등록하는 반면,@Component
는 클래스에 직접 적용되어 해당 클래스의 인스턴스 자체를 빈으로 등록한다. - 자동성:
@Component
는 컴포넌트 스캔을 통해 자동으로 빈 등록이 이루어지는 반면,@Bean
은 개발자가 명시적으로 메소드를 정의하고 반환 타입을 빈으로 등록해야 한다. - 사용 상황:
@Bean
은 주로 외부 라이브러리나 복잡한 객체 생성 로직을 포함한 경우 사용되고,@Component
는 개발자가 직접 작성한 클래스를 자동으로 빈으로 등록하고자 할 때 사용된다.
이러한 차이점을 이해하고 상황에 맞게 적절히 선택하여 사용하면 스프링 기반의 애플리케이션을 보다 효율적으로 개발할 수 있다.
Spring Web MVC에서 요청 마다 Thread가 생성되어 Controller를 통해 요청을 수행할텐데, 어떻게 1개의 Controller만 생성될 수 있는가?
Spring Web MVC 프레임워크에서는 각 요청마다 별도의 스레드가 생성되어 처리되지만, Controller 객체 자체는 기본적으로 싱글톤(singleton)으로 생성된다. 이는 Spring의 기본 빈 스코프인 ‘singleton’ 때문이다. 이러한 구조가 가능한 이유와 세부적인 메커니즘은 다음과 같다:
- 싱글톤 스코프: 스프링 컨테이너는 기본적으로 각 빈(bean)을 싱글톤으로 관리한다. 즉, 애플리케이션의 생명주기 동안 각 빈의 인스턴스는 단 하나만 생성되며, 모든 요청에서 이 인스턴스를 공유한다. Controller도 예외는 아니다.
- 스레드 안전성: Controller가 싱글톤으로 운영되면서도 여러 요청을 동시에 처리할 수 있는 이유는 스프링이 멀티스레드 환경에서 스레드 안전성(thread safety)을 유지할 수 있도록 설계되었기 때문이다. Controller 내부의 상태를 요청 간에 공유하지 않거나, 상태가 공유되는 경우 스레드 안전한 방식으로 관리되어야 한다.
- 무상태 디자인: 대부분의 Controller는 무상태(stateless)로 설계된다. 즉, 특정 요청의 상태 정보를 Controller의 필드에 저장하지 않는다. 상태 정보는 대신 요청 객체, 세션, 데이터베이스 등에 저장되어 요청마다 독립적으로 관리된다. 이로 인해 동일한 Controller 인스턴스가 여러 요청에 대해 동시에 사용되어도 각 요청 간에 데이터가 충돌하는 일이 없다.
- 의존성 주입(Dependency Injection): 스프링 프레임워크는 의존성 주입을 통해 Controller와 필요한 의존 객체들을 연결한다. 이러한 방식은 Controller가 특정 구현에 강하게 결합되는 것을 방지하고, 유연성 및 재사용성을 높인다. 또한, 의존성 주입을 통해 필요한 서비스나 컴포넌트의 인스턴스를 요청마다 새로 생성할 필요 없이 재사용할 수 있게 된다.
- 스레드 로컬(Thread Local) 사용: 필요한 경우, 스프링은 스레드 로컬을 사용하여 요청마다 스레드에 고유한 데이터를 저장할 수 있게 해준다. 이는 특정 요청에만 제한된 정보를 스레드에 안전하게 저장하고 접근할 수 있게 해준다.
이와 같은 메커니즘 덕분에 스프링 MVC 프레임워크는 각 요청을 개별적으로 처리하면서도 효율적으로 리소스를 관리하고, Controller의 싱글 인스턴스를 안전하게 재사용할 수 있다.
싱글톤 패턴이 무엇인지 알고, 스프링에서 대표적으로 사용되는 부분에 대해 설명해보시오
싱글톤 패턴은 디자인 패턴 중 하나로, 클래스의 인스턴스가 애플리케이션 내에서 하나만 존재하도록 보장하는 패턴이다. 이는 전역 상태를 관리하거나 여러 구성 요소 간에 공유되어야 하는 리소스가 있는 경우 유용하다.
싱글톤 패턴의 특징
- 유일한 인스턴스: 클래스의 단 하나의 인스턴스만을 생성하고, 이 인스턴스에 대한 전역 접근 지점을 제공한다.
- 지연 초기화(Lazy Initialization): 인스턴스가 필요할 때까지 생성을 지연시킴으로써 리소스를 효율적으로 사용할 수 있다.
- 메모리 절약: 동일한 객체를 반복해서 생성하지 않고, 한 번 생성된 인스턴스를 재사용함으로써 메모리 사용을 최소화한다.
스프링에서의 싱글톤 사용
스프링 프레임워크는 기본적으로 모든 빈(Bean)을 싱글톤 스코프로 관리한다. 이는 다음과 같은 장점을 제공한다:
- 성능 향상: 각 빈에 대해 단 하나의 인스턴스만 생성하므로, 생성 비용이 큰 객체의 반복적인 생성으로 인한 성능 저하를 방지한다.
- 공유 리소스 관리: 서비스, 리포지토리, 컨트롤러 등의 컴포넌트를 여러 곳에서 공유할 수 있으므로, 애플리케이션 전체에서 일관된 상태를 유지할 수 있다.
- 의존성 관리: 스프링의 의존성 주입 기능은 싱글톤 빈을 사용하여, 다양한 컴포넌트 간의 의존성을 효과적으로 관리하며, 설정과 사용을 간소화한다.
예제
예를 들어, 스프링 MVC 프레임워크에서 Controller, Service, Repository 등은 일반적으로 싱글톤으로 등록되어 사용된다. 이들 각 컴포넌트는 애플리케이션 내에서 하나의 인스턴스만 존재하며, 모든 요청과 작업에 대해 해당 인스턴스를 공유한다.
@Service
public class UserService {
// 여기서 UserService 클래스는 싱글톤으로 관리된다.
}
싱글톤 패턴은 전역 상태를 관리할 때 유용하지만, 상태를 공유하는 구성 요소에서는 스레드 안전성을 보장해야 할 필요가 있으며, 설계 시 주의가 필요하다. 스프링은 이러한 싱글톤의 관리를 용이하게 해주며, 애플리케이션의 구성과 성능 최적화에 크게 기여한다.
대용량 트래픽에서 장애가 발생하면 어떻게 대응할 것인지 논리적으로 대답해보시오
대용량 트래픽에서 장애가 발생했을 때 효과적으로 대응하기 위한 접근 방법은 여러 단계로 나누어 설계할 수 있다. 이러한 대응은 예방, 감지, 대응, 복구의 단계로 구성된다.
1. 예방 단계
- 리소스 확장성: 시스템의 확장성을 고려하여 설계해야 한다. 클라우드 인프라를 사용하는 경우, 자동 스케일링 기능을 활용하여 필요에 따라 리소스를 자동으로 추가하거나 제거할 수 있다.
- 로드 밸런싱: 로드 밸런서를 사용하여 네트워크 트래픽을 여러 서버에 분산시켜 한 서버에 과부하가 걸리는 것을 방지한다.
- 캐싱: 자주 요청되는 데이터나 계산 결과를 캐시에 저장하여 반복적인 데이터 처리 요구를 최소화한다. 이는 응답 시간을 단축시키고 서버 부하를 줄일 수 있다.
- 비동기 처리: 메시지 큐 등을 활용하여 작업을 비동기적으로 처리함으로써, 높은 트래픽이 발생하는 작업을 분산시키고 시스템의 부하를 감소시킨다.
2. 감지 단계
- 모니터링 시스템: 서버의 CPU 사용률, 메모리 사용량, 네트워크 트래픽 등을 지속적으로 모니터링하는 시스템을 구축한다. 이를 통해 장애를 조기에 감지할 수 있다.
- 알림 시스템: 장애 감지 시 즉시 관리자나 개발자에게 알림을 보내는 시스템을 구현하여 신속한 대응이 가능하도록 한다.
3. 대응 단계
- 트래픽 제한: 과도한 트래픽이 확인될 경우, 비정상적인 트래픽이나 요청을 필터링하거나 일시적으로 요청을 제한하는 방법을 사용한다.
- 문제 분리: 장애가 발생한 서비스나 구성 요소를 신속히 분리하여 전체 시스템에 미치는 영향을 최소화한다.
- 롤백 기능: 새로운 업데이트나 변경 사항이 문제를 일으킨 경우, 이전 상태로 롤백할 수 있는 기능을 구현한다.
4. 복구 단계
- 데이터 백업 및 복구: 정기적으로 데이터를 백업하고, 필요한 경우 이를 빠르게 복구할 수 있는 절차를 마련한다.
- 복구 계획: 장애가 발생한 후, 시스템을 원래 상태로 복구하기 위한 계획을 사전에 수립하고, 이를 정기적으로 검토 및 업데이트한다.
이러한 단계를 통해 대용량 트래픽에서 발생할 수 있는 장애를 효과적으로 예방, 감지, 대응, 복구할 수 있다. 각 단계는 서로 연관되어 있으며, 전체적인 장애 대응 체계를 강화하는 데 중요한 역할을 한다.
API가 무엇인지, RESTAPI와 RESTful API는 무엇인지 설명하고 차이를 설명하시오
API(Application Programming Interface)는 소프트웨어나 애플리케이션 간의 상호작용을 가능하게 하는 인터페이스다. API는 한 시스템이 다른 시스템의 기능이나 데이터를 사용할 수 있도록 메소드와 프로토콜을 제공한다. 이를 통해 개발자는 복잡한 기능을 직접 구현하지 않고도 외부 라이브러리나 서비스를 통해 필요한 기능을 사용할 수 있다.
REST API
REST(Representational State Transfer)는 분산 시스템을 위한 아키텍처 스타일 중 하나로, API 설계의 지침을 제공한다. REST API는 HTTP 메소드(GET, POST, PUT, DELETE 등)를 사용하여 리소스에 접근하고 조작하는 웹 서비스를 구현한다. REST API의 주요 특징은 다음과 같다:
- 리소스 지향: 각 리소스는 고유한 URI(Uniform Resource Identifier)에 의해 식별되며, 리소스의 상태는 클라이언트에게 전달되는 데이터(주로 XML 또는 JSON) 형태로 표현된다.
- 무상태성(Statelessness): 각 요청이 독립적이며, 이전 요청의 정보를 저장하고 있지 않다. 서버는 각 요청을 완전히 별개로 처리한다.
- 캐시 가능: 응답은 캐시가 가능하다고 명시될 수 있으며, 이를 통해 효율성과 확장성을 높일 수 있다.
RESTful API
RESTful API는 REST 원칙을 엄격하게 준수하는 API를 의미한다. 모든 REST 원칙을 지키는 API는 RESTful하다고 평가받는다. RESTful API는 다음과 같은 특징을 가진다:
- 클라이언트-서버 구조: 서버는 API를 통해 정보를 제공하고, 클라이언트는 그 정보를 사용한다.
- 계층화 시스템: 클라이언트는 종단 서버에 직접 연결되지 않을 수도 있으며, 중간 서버를 통해 요청이 전달될 수 있다.
- 균일한 인터페이스: 리소스에 대한 인터페이스가 일관적이며, 시스템 내부 구조에 영향을 받지 않는다.
차이점
- REST API는 REST 아키텍처 스타일을 따르는 API를 일컫는 보다 일반적인 용어다. REST 원칙을 어느 정도 따르고 있으나 모든 원칙을 엄격히 준수하지는 않을 수 있다.
- RESTful API는 REST 아키텍처의 모든 원칙을 엄격히 준수하는 API를 의미한다. 따라서 모든 RESTful API는 REST API이지만, 모든 REST API가 RESTful한 것은 아니다.
이러한 차이를 이해하는 것은 API를 설계하거나 선택할 때 중요하며, 명확한 기준에 따라 API를 구현하고 사용하는 데 도움을 준다.
@Controller와 @RestController의 차이가 무엇인지 설명하시오.
Spring Framework에서 @Controller
와 @RestController
어노테이션은 웹 애플리케이션에서 컨트롤러 레이어를 구현하는 데 사용되며, 각각의 어노테이션은 서로 다른 사용 사례와 기능을 제공한다.
@Controller
- 목적:
@Controller
어노테이션은 전통적인 Spring MVC 컨트롤러로 사용되며, 주로 뷰 템플릿을 반환하는 데 사용된다. 이 어노테이션이 적용된 클래스는 주로 HTTP 요청을 처리하고, 모델 데이터를 뷰에 전달하여 HTML 페이지를 생성하는 데 사용된다. - 데이터 반환:
@Controller
를 사용할 경우, 메소드가 데이터를 반환하더라도 그 데이터는 일반적으로 뷰 이름으로 해석된다. 데이터를 HTTP 응답 본문에 직접 포함시키기 위해서는 메소드에@ResponseBody
어노테이션을 추가해야 한다.
@RestController
- 목적:
@RestController
는@Controller
와@ResponseBody
를 합친 것으로 볼 수 있으며, JSON이나 XML 등의 RESTful 웹 서비스를 구축하는 데 적합하다. 이 어노테이션은 주로 데이터를 반환하고 API를 통해 통신하는 애플리케이션에 사용된다. - 데이터 반환:
@RestController
어노테이션을 사용하면 클래스 내의 모든 핸들러 메소드가 기본적으로@ResponseBody
를 가지게 되어, 메소드가 반환하는 데이터는 직접 HTTP 응답 본문으로 전송된다. 이는 클라이언트에게 JSON 또는 XML 형태로 데이터를 반환할 때 매우 유용하다.
예시
다음은 @Controller
와 @RestController
의 사용 예를 보여준다:
@Controller 예시
@Controller
public class MyViewController {
@RequestMapping("/home")
public String home(Model model) {
model.addAttribute("message", "Hello World");
return "home"; // 뷰 이름을 반환 (예: home.html)
}
}
@RestController 예시
@RestController
public class MyRestController {
@RequestMapping("/data")
public Map<String, String> data() {
Map<String, String> data = new HashMap<>();
data.put("message", "Hello World");
return data; // 데이터를 직접 반환, 기본적으로 JSON 형태로 클라이언트에 전송
}
}
결론
@Controller
와 @RestController
의 주요 차이는 반환되는 데이터의 처리 방식과 주로 사용되는 컨텍스트에 있다. @Controller
는 뷰를 반환하는 서버 사이드 페이지 렌더링에 적합하고, @RestController
는 JSON이나 XML을 반환하는 RESTful 서비스에 적합하다. 선택은 애플리케이션의 목적과 요구에 따라 결정되어야 한다.
@RequestBody와 @Requestparam, @ ModelAttribute의 차이를 설명하시오
Spring Framework에서 @RequestBody
, @RequestParam
, @ModelAttribute
어노테이션들은 HTTP 요청을 처리할 때 사용자 입력을 받아들이는 방법을 지정하는 데 사용된다. 각각의 어노테이션은 다른 유형의 요청 데이터를 처리하며, 서로 다른 용도로 사용된다.
@RequestBody
- 목적:
@RequestBody
어노테이션은 HTTP 요청의 본문(body)을 Java 객체로 직접 매핑하는 데 사용된다. 주로 JSON 또는 XML과 같은 복잡한 데이터 구조를 받을 때 사용된다. - 사용 사례: 클라이언트가 서버로 JSON이나 XML 형식의 데이터를 보내고, 이를 서버에서 Java 객체로 직접 변환해야 할 때 사용된다.
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.saveUser(user);
}
@RequestParam
- 목적:
@RequestParam
은 HTTP 요청의 쿼리 파라미터(query parameters) 또는 폼 데이터(form data)를 메소드 파라미터에 바인딩하는 데 사용된다. 주로 간단한 데이터 타입이나 단일 값 처리에 적합하다. - 사용 사례: 웹 폼 제출 또는 URL 쿼리 파라미터를 통해 값을 전달받을 때 사용된다.
@GetMapping("/user")
public User getUser(@RequestParam String userId) {
return userService.getUserById(userId);
}
@ModelAttribute
- 목적:
@ModelAttribute
는 HTTP 요청의 파라미터를 객체의 필드와 매핑하여 객체를 생성하거나 업데이트하는 데 사용된다. 주로 복잡한 객체를 폼 데이터와 바인딩할 때 사용된다. - 사용 사례: HTML 폼 데이터가 복잡한 객체에 매핑되어야 할 때, 즉 여러 필드가 하나의 객체로 그룹화되어 전송될 때 유용하다.
@PostMapping("/register")
public String registerUser(@ModelAttribute User user) {
userService.saveUser(user);
return "redirect:/home";
}
차이점
- @RequestBody는 요청의 본문을 객체로 직접 변환하므로 주로 JSON 또는 XML과 같이 복잡한 구조의 데이터를 처리할 때 사용된다.
- @RequestParam은 개별적인 파라미터 값들을 메소드의 파라미터로 전달받기 위해 사용되며, URL 쿼리 파라미터나 폼 데이터를 처리하는데 적합하다.
- @ModelAttribute는 HTTP 요청의 파라미터를 객체의 필드에 바인딩하여 객체를 생성하거나 업데이트하는 데 사용되며, 주로 HTML 폼과 연결된 복잡한 객체를 다룰 때 사용된다.
이러한 차이를 이해하고 적절한 어노테이션을 사용하면, 요청 데이터를 효율적으로 처리하여 애플리케이션의 정확성과 유지보수성을 향상시킬 수 있다.