Interview Questions 3
Spring?
Java 기반의 웹 오픈소스 프레임워크로 OOP을 활용할 수 있다. 또한, IoC, DI, AOP 등의 특징을 가진다.
IoC: 프레임워크에 의해 제어되는 구조 DI: 인터페이스에 의존하는 객체에 대해 구현 클래스를 주입한다. AOP: 애플리케이션 전범위에서 트랜잭션, 로깅과 같이 비즈니스 로직이 아닌 기술 지원 로직에 대한 일괄적인 관리가 가능하다.
SpringBoot?
처음 부터 Spring 만을 이용해서 프로젝트를 개발하면 Gradle, Tomcat 과 같이 초기에 세팅해줘야할게 많다. 이러한 Configuration에 대해 Spring-Boot을 사용하면 간편하게 Spring 프로젝트를 시작할 수 있다. 또한, 내장 tomcat 웹서버를 활용하여 별도의 웹서버의 실행이 요구되지 않는다.
Servlet
HTTP Request을 처리하기 위해 Java에서 제공하는 웹 기반 기술이다.
Client에서 전달된 Http Request는 WAS server가 생성한 Split Container로 전달되는데, 이때 Http Request 정보를 분석해서 HttpServletRequest가 생성된다. 그러면 서블릿에서는 HttpServletRequest을 이용해서 필요한 정보들을 추출해서 비즈니스 로직을 수행한다음 HttpServletResponse 객체에 응답을 담아서 처리한다.
Spring DI/IoC
IoC는 Inversion of Controls의 약자로 애플리케이션이 직접 실행의 흐름을 가져가는 것이 아닌, 프레임워크에 제어의 흐름을 넘겨서 프레임워크에 의해 동작되는 것을 의미한다. Spring은 Application Context 혹은 Autowired으로 설정된 의존성을 파악해서 필요한 DI를 제공한다.
Spring Bean
객체가 생성되어 Spring Container에 의해 관리되고 있는 상태를 Spring Bean이라고 한다. Spring Container 내부에서 싱글톤 방식으로 관리된다.
Spring Bean 생성 과정
- Spring Container 실행
- Spring Bean 생성
- 의존성 부여
- 객체 초기화 콜백 호출
- 사용
- 객체 소멸 콜백 호출
- 객체 소멸
Spring에서는 @PostConstruct, @PreDestory을 이용해서 초기화 과정, 소멸 과정에서 호출되는 메소드를 지정할 수 있다.
Spring Bean Scope
Spring Bean은 기본적으로 singleton 방식으로 관리되는데, 경우에 따라서 초기화 콜백까지 관리되는 prototype, 사용자의 요청마다 생성되는 request와 같이 어플리케이션 범위보다 짧은 범위를 가지는 Spring Bean도 제공한다.
IoC Container의 역할
Spring Bean을 singleton 형태로 관리해주며, 의존관계가 필요한 객체에 대해 DI를 제공한다.
DI 방식
- 생성자 DI: private final로 설정하여 생성과 동시에 초기화를 수행한다. final을 통해 무조건 할당해줘야한다는 부분에서 누락의 문제가 발생하지 않고, 순환 참조 문제가 발생하지 않는다.
- 수정자 함수 DI: setter 함수를 통해 의존관계를 부여한다.
- 필드 DI: 필드 단위로 의존관계를 부여한다. 단, Spring을 제외한 환경에서는 동작하지 않는다. (Spring Container가 필수이다.)
constructor와 달리, 수정자, 필드를 활용하면 의존관계를 런타임 시 변경할 수 있다.
Autowiring
의존관계가 필요함을 명시하는 annotation으로, Spring Container에서 해당 클래스 타입을 만족하는 Bean을 찾아서 의존관계를 부여한다.
Dispatcher Servlet의 동작과정
- 모든 요청은 Dispatcher Servelet으로 전송된다.
- http request을 분석해서 해당 request을 처리할 수 있는 handler mapping을 찾는다.
- 해당 handler을 처리할 수 있는 adapter을 찾는다.
- adapter을 통해 handler을 수행한다.
- handler의 반환형은 ModelAndView을 반환받는다.
- ViewResolver을 통해 ModelAndView에서 ViewPath을 추출해서 해당 View을 Rendering한다.
Front Controller Pattern
Controller에서 반복적으로 처리되어야 하는 HttpServeletResponse, HttpServeletResponse, View page forwarding 과 같은 공통적인 로직에 대해서 일괄적으로 처리하기 위해 Front Controller을 생성해서 모든 요청에 처리를 수행합니다. Front Controller을 통해 보안, 국제화, 라우팅과 같은 일반적인 기능을 한곳에서 처리 가능합니다.
Servelet Filter vs Interceptor
Filter는 javax.servlet 라이브러리에서 제공하는 것으로 dispatcher servelet 외부에서 동작하며 Spring이 활용되지 않는 보안과 일반적인 공통 로직을 처리한다.
Interceptor은 dispatcher Servelet 내부에서 동작하는 것으로 Spring 환경에서 동작한다. 그렇기 때문에 Filter보다 더 확장성있는 기능을 제공한다.
Spring CORS
ServletFilter을 이용해서 CORS을 설정하거나, Controller 클래스에 대해서 @CrossOrigin annotationd를 붙여서 해결할 수 있다.
Bean/Component
두 가지 방식 모두 Spring Bean을 등록하기 위해 사용하는 annotation이지만, @Bean은 Method 기반의 Bean을 등록하게 되고, @Component을 활용하면 Class 기반의 Spring Bean으로 등록할 수 있습니다.
POJO
PLain Old Java Object으로 Java API 외에는 어떠한 것에도 종속적이지 않습니다. 특정 환경에 종속적이지 않기 때문에 테스트환경에서 문제가 발생하지 않는다. Domain 과 Business Logic에서 주로 사용된다.
Controller 1개가 실행되는 것 보장?
Spring Container에 등록된 Controller는 singleton 방식으로 동작되어 모든 thread에서 공유된다.
@Transactional 처리
Spring에서는 @Transactional 표시를 통해 해당 메소드/클래스가 트랜잭션 내부에서 동작해야함을 명시한다. 이때, @Transactional이 명시된 메소드에 대해서는 AOP을 통해 Proxy가 생성된다. Proxy는 target method 전에 실행되여 transaction 관련 설정을 처리한 다음 target method을 호출한다.
이때, 특정 target을 대상으로한 method을 직접 호출 했을때만 AOP가 동작한다. 다른 method에서 @Transactional이 적용된 method을 호출하면 AOP가 동작하지 않는다.
JPA 영속성 컨텍스트의 장점
- 1차 캐시: 객체를 조회하기 위해 우선 적으로 1차 캐시를 확인하고 없으면 DB로 조회를 수행한다.
- 변경 감지: 영속 상태인 엔티티에 대해서 1차 캐시에 있는 값과 비교하여 수정이 발생하면 1차 캐시의 값을 수정한다.
- 지연 로딩: 실제로 객체를 사용하기 전까지 엔티티 로딩을 유보한다.
- sql 지연 쓰기: 트랜잭션에 대해 sql 쓰기 지연을 제공하여, commit을 수행할때 한번에 DB에 sql을 적용한다.
- 동일성 보장: 1차 캐시를 통해 조회된 entity에 대해 같은 객체 임을 보장한다.
JPA n+1 문제
1번의 jpql 호출을 통해 N개의 엔티티가 조회됐는데, 해당 엔티티와 연관된 데이터가 즉시로딩으로 설정된 경우 다시 N번의 쿼리가 호출된다.
이러한 N+1 문제를 해결하기 위해
- fetch join을 통해 한번에 연관된 데이터까지 모두 가져오는 것을 고려
- BatchSize을 지정하여 지정한 batch size 만큼씩 데이터를 가져와서 N+1 문제를 완화
댓글남기기