Spring 면접대비 질문
Spring
정의
뭐 지원하는지
IoC(bean)
DI
AOP
등의 특징을 가지는 프레임워크
Bean
정의
spring에서 plain old java object - 그냥 객체 - 를 bean이라고 한다.
IoC Container가 관리 및 생성한다.
@Component를 사용한 class들만 bean으로 정의된다. 이 bean들은 기본적으로 singleton이다.
IoC Container가 DI해주기도 한다.
IoC
정의
제어 역전 - 프로그램 제어권이 programmer가 아니라 framework인 spring에 있는 것. 개발자는 framework의 형식에 맞춰 개발하게 된다.
AOP
정의
aspect oriented programming
공통 관심사를 분리해 모듈화하는 것. 인증/로깅 등에 사용.
어떤 로직에 대해 핵심 관점과 부가 기능으로 나누고, 부가 기능을 모듈화하는 것. 예를 들어 logging 등.
Filter vs Interceptor
filter는 dispatcher servlet에 들어가기 전에 요청을 가로챔. spring 범위의 밖임. 따라서 business logic과는 관계 없으므로 인증, xss, 인코딩 변환 등을 사용.
interceptor는 dispatcher servlet에 들어간 후의 요청을 가로챔. 때문에 로그인, 권한 체크 등을 함.
(나올 때는 반대)
DI
정의
spring IoC Container
종류 3가지
dependency injection
필요한 객체를 직접 생성하는 것이 아니라 외부에서 주입하는 것.
각 bean들의 dependency는 IoC Container가 설정해줌.
등록한 bean들끼리 dependency를 넣어준다.
각 bean의 과정 : container 생성 - bean 생성 - dependency inject - 초기화 - 사용 - 소멸 전 callback - 종료 / container가 관리.
구성 요소를 변경하더라도, 다른 부분의 코드를 변경하지 않는 것. DI를 쓰면 dependency가 있는 object를 다른 코드로 쉽게 바꿀 수 있다. 따라서 dependency가 느슨해지기에 유지보수를 쉽게 할 수 있게 된다.
dependency injection의 방법은 contructor, setter, field injection 3가지가 있다. @autowired를 넣는 위치가 constructor는 costructor에 넣는 방식, setter는 setter method를 사용하는 방식, field는 field에 넣는 방식이다.
일반적으로는 constructor injection을 사용한다고 한다.
- final로 선언해 immutable 보장 가능
- circular dependency 컴파일 시점에 확인 가능
field injection의 경우 실행 시점에 circular dependency 확인 가능.
Dispatcher Servlet 흐름
- DispatcherServlet이 client request를 받음
- HandlerMapping이 request url에 해당하는 controller 찾음
- HandlerAdapter에 처리 요청을 보냄
- controller가 로직을 처리하고 결과를 HandlerAdapter로 줌
- DispatcherServlet은 결과를 ViewResolver로 보내고, ViewResolver는 jsp파일의 경로를 찾는다.
Persistence Context
정의
장점
entity를 저장하는 환경.
DB의 캐시 역할을 한다.
쓰기 지연 : write한 것들이 DB에 각각 들어가지 않고 모아서 넣어주기 때문에 내부적인 최적화가 이루어진다. (캐시, 쓰기 지연 등)
위와 같은 백락으로, persistence에서 DB로 commit 보내는 시점에 스냅샷과 비교해서 필요한 만큼만 sql을 보낸다.
지연 로딩 : 필요할 때 해당 data를 가져온다.
쓰기 지연 : 영속된 상태에서는 entity가 DB에 반영되었을 수도 있고 그렇지 않을 수도 있다. 내부적으로 값을 가지고 있기 때문. persistence context가 flusth하면 DB에 작업 내용을 반영함.
- 비영속 : 객체는 생성됨, persistent context에 속하지 않음
- 영속 : persistence ontext가 entity를 관리.
- 준영속 : persistence context에서 관리되던 것이 더이상 관리되지 않는 상태. 이 상태에서는 변경사항은 DB에 반영됨.
지연 로딩 떄문에 N+1 문제가 생길 수 있다. join한 것들을 가져올 때 N개를 N번의 쿼리로 가져오는 경우가 그렇다. 해결하기 위해 fetch join을 쓴다.
패키지 구성
종류
계층형
도메인형 : 도메인형 구조를 사용하면 코드의 응집도가 높고, 도메인 그 자체의 흐름을 이해하기 쉽습니다.
Spring Security
filter에서 처리한다.
1. filter가 요청을 가로채면 정보를 토대로 인증용 객체 Token object를 생성.
2. 이후 authentication manager의 인증 method를 호출한다. 해당 method 내부에서는 개발자가 구현한 UserDetailsService method 내부에서 검증을 진행한다.
3. UserDetailService는 UserDetail이라는 객체를 반환하고, securitycontext에 userdetail 정보가 들어간다.
그러면 내부적으로 filter에서 걸리고, 올바르지 않으면 return 올바르면 구현한 부분에서 userDetail을 securitycontext에 넣어준다.
DAO, DTO, BO, VO
dao : data access object, DB 데이터 접근/조작을 위해 사용
dto : data transfer object, layer 간에 데이터 교환을 위해 사용 (getter, setter만 사용)
vo : value object, 값을 나타내는 객체
Spring vs Spring Boot
spring 같은 경우는 설정을 많이 해 줘야 한다. bean이 어떤 package에 있고 어떤 이름을 가지는지 application.xml에 직접 등록을 해 줘야 한다. web.xml에 각 library에 대한 dependency도 직접 등록을 해 줘야 했다. 서버도 톰캣 따로 띄워 줘야 했다.
spring boot는 이러한 과정이 매우 간소화되었다. auto config 과정 (component scan 등)을 통해 bean 등록 자동화, 라이브러리도 가독성 좋게 관리, 내장 서버 등이 있다.
Spring 장점 & thread 동작
spring
- spring은 CPU 작업이 많은 경우가 좋다. 연산이 많은 경우 thread를 사용해 명시적으로 처리할 수 있기 때문에 효율적.
- type-safe하다.
- 실행에 오래 걸린다. (JVM, GC)
- 플랫폼 독립. (jvm 위에서 돌 수 있음)
- thread 생성 위해서는 개발자의 관리가 필요함.
spring은 thread pool을 사용해 thread를 관리함. 내부적으로 몇 개의 thread를 미리 생성해 둠. 이후 필요한 작업에 할당했다가 돌려 받음. (thread를 생성/삭제하는 게 OS, JVM에 로드를 많이 주고, 무한히 생성할 수도 있기 때문.)
1. 초기에 정해진 크기만큼 thread 생성함
2. 사용자 요청이 들어오면 queue에 담아두고, idle 상태(놀고 있는) thread가 있으면 queue에서 꺼내서 작업을 thread에 할당함.
- idle인 thread가 없다면 작업은 queue에서 대기, 만약 queue가 가득 차면 thread 새로 생성.
- task 완료 시 thread는 idle 상태로 돌아가고, queue가 비고 thread가 초기 개수보다 더 많다면 destroy.
=> 미리 만들어 놓고, 필요한 작업에 할당했다가 돌려받음.
JPA & Transactional & Test annotation
@transational
해당 메소드가 transation이 되게 보장해줌. 여러 DB 쿼리가 있으면 이것들을 transaction으로 묶음. 하나라도 문제 발생 시 롤백. 종료 시 commit().
여러 개의 transactional이 있는 경우, 격리 수준을 사용해서 해당 리소스에 접근. 순서는 jvm 스케쥴링에 따름.
rollbackfor option : 기본적으로 unchecked exception만 롤백하기 때문에 exception도 롤백하게 지정
readonly option:
(일반적으로) entity가 영속성에 영속될 때, 해당 entity의 상태를 snapshot으로 남긴다. snapshot과 entity 상태를 비교해 변경된 내용만 update query를 모아 DB로 날린다.(이게 dirty checking이다!) transactional이 붙은 method는 트랜잭션 commit 시 DB에 flush함.
readonly true : dirty checking 발생 X. read 한 이후 DB로 flush하지 않는다. (snapshot을 찍지 않기 때문에 변경사항 감지 X. 때문에 메모리 절약도 가능) 때문에 변경사항 반영 안 되는 것으로 알고 있다.
---
slice test : 특정 계층만 처리 가능. @springboottest : 전체, @webmvctest: controller, 등
@test
junit에서 test annotation 다 모아서 테스트 돌려줌.
@springboottest
spring에서 bean 등록한 것들 "다" 모아서 injection해줌.
테스트 코드에서 @transactional 쓰면 쿼리 날린 것 다 롤백해 줌. (안붙이면 롤백안됨)
bean 등록한거에서 가져오고 싶으면 @autowired 쓰면 됨
@webmvctest
controller 관련만 로드함. @mockbean 만들고 리턴값 정의해서 써야 함.