지나공 : 지식을 나누는 공간

[직무인터뷰] Spring과 DB 이야기 - 2편 본문

Tech Interview

[직무인터뷰] Spring과 DB 이야기 - 2편

해리리_ 2021. 6. 6. 17:43

스프링 IoC 컨테이너가 빈을 등록하는 원리는?

스프링은 개발자가 직접 만든 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다. 또 의존 관계도 자동으로 주입하는 @Autowired 라는 기능도 제공한다. 컴포넌트 스캔을 통한 자동 빈 등록 외에도 직접 빈을 등록할 수도 있다.

 

1. 컴포넌트 스캔 (자동 의존관계 주입)

2. 직접 빈 등록 - xml 또는 설정 파일 용도의 클래스를 생성하여 @Configuration을 붙이고 직접 등록할 메소드에 @Bean을 명시해서 할 수 있음. 

 

@SrpingBootApplication안에 @ComponentScan이 있고, 이 어노테이션은 여기서부터 모든 하위 패키지의 클래스를 훓으면서 @Component가 붙은 애들을 찾아 빈으로 등록하겠다는 의미이다.

@Configuration 안에 @Component가 들어 있음. @Component는 스캔의 대상을 의미한다.

 

아, 참고로 @SpringBootApplication에는 싱글톤을 보장해줄 @Configuration도 들어있고, 자동 빈 등록을 위한 컴포넌트 스캔 시작위치를 알리는 @ComponentScan도 들어있다!

 

스프링 빈 등록

빈 이름은 메소드 이름(소문자 시작으로 이름을 바꿈)으로, 그에 따른 빈 객체는 반환되는 객체로 등록한다.


빈을 주입하는 가장 좋은 방법은?

의존관계 주입에는 네 가지 방법이 있다.

  • 생성자 주입
  • 수정자 주입 (setter를 통한)
  • 필드 주입
  • 일반 메서드 주입

생성자 주입은 생성자에 @Autowired를 달아서 구현할 수 있는데, 생성자가 딱 1개만 있으면 @Autowired를 생략해도 자동 주입된다.

 

가장 좋은 방법은 생성자 주입이다. 이유는

  • 대부분의 의존관계 주입은 한번 일어나면 애플리케이션 종료시점까지 의존관계를 변경할 일이 없고 오히려 대부분의 의존관계를 애플리케이션 종료까지 변하지 않게 해야 한다.
  • 수정자 주입을 사용하려면 setter 메소드를 public으로 열어둬야 하는데 이러면 외부에서 마구 변경할 수 있어서 위험하다.
  • 생성자 주입은 객체 생성 시에 딱 1번만 호출되니까 불변으로 설계할 수 있다.

빈 스코프란? (빈 범위, 빈 생성시점과 관련)

말 그대로 빈이 존재할 수 있는 범위를 말한다. 스프링은 아래와 같은 다양한 스코프를 지원한다.

@Scope라는 어노테이션을 통해 적용할 수 있다. 예) @Scope("prototype")

  • 싱글톤 : 기본 스코프, 스프링 컨테이너의 시작부터 종료까지 유지되는 가장 넓은 범위의 스코프.
  • 프로토타입 : 스프링 컨테이너가 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는, 매우 짧은 범위의 스코프.
  • 웹 관련 스코프
    • request : 웹 요청이 들어오고 나갈 때까지 유지되는 스코프.
    • session : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프.
    • application : 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프.

예를 들어 프로토타입 스코프를 가진 빈이라고 할 때, 싱글톤 스포크의 빈이라면 스프링 컨테이너에서 조회 시에 항상 같은 인스턴스를 반환하는 반면 프로토타입 빈은 항상 새로운 인스턴스를 생성해서 반환한다.

 

핵심은 스프링컨테이너가 프로토타입 빈을 생성, 의존관계 주입, 초기화 까지만 처리하는 점이다. 클라이언트에 해당 빈을 반환한 뒤 스프링 컨테이너는 더는 그 빈을 관리하지 않고, 이제 이 프로토타입 빈을 관리할 책임은 이걸 받은 클라이언트에 있다.


빈의 생성시점에 대해 말해봐라

싱글톤 빈은 스프링 컨테이서 생성 시점에 초기화 메소드가 실행되지만, 프로토타입 스코프의 빈은 스프링 컨테이너에서 빈을 조회할 때 생성되고, 초기화 메소드도 실행된다.

프로토타입 빈을 2번 조회하면 각가 완전히 다른 스프링 빈이 생성되고 초기화도 2번 실행된다.

 

프로토타입 빈의 특징 정리

  • 스프링 컨테이너에 조회 요청할 때마다 새로 생성됨
  • 종료 메소드가 호출되지 않고 이 프로토타입 빈을 조회한 클라이언트가 관리해서 종료 메소드 호출도 클라이언트가 해야 한다.

빈의 라이프사이클에 대해 아는가?

객체 생성 - 의존관계 주

 


Spring MVC란?

웹 애플리케이션 개발을 위한 MVC 패턴을 기반으로 Model - View - Controller로 구성된 웹 프레임워크.

Model : 데이터를 저장하는 컴포넌트

View : 사용자 인터페이스 컴포넌트

Controller : 사용자의 요청을 처리하고 Model과 View를 중계하는 컴포넌트

 

1. 클라이언트가 URL을 통해 요청을 전송

2. 디스패처 서블릿이 핸들러매핑을 통해 어떤 컨트롤러에게 온 요청인지 검사

3. 디스패처 서블릿이 핸들러어댑터한테 '요청의 전달'을 맡김

4. 핸들러어댑터가 해당 컨트롤러에게 요청을 전달

5. 컨트롤러는 요청에 맞는 비즈니스 로직을 처리한 뒤 반환할 뷰의 이름을 반환

6. 디스패처 서블릿은 뷰리졸버를 통해 해당 이름을 가진 뷰를 찾음

7. 디스페처 서블릿은 컨트롤러한테 받은 데이터를 뷰에 추가해서 반환

8. 데이터가 추가된 뷰가 반환됨

 

DispatcherServlet : 클라이언트의 요청을 먼저 받아들이는 서블릿으로 요청에 맞는 컨트롤러에게 요청을 전달한다.

HandlerMapping : 해당 요청이 어떤 컨트롤러에게 온 요청인지 검사한다.

Controller : 클라이언트의 요청을 받아 처리한 뒤 결과를 디스패처 서블릿에게 전달한다.

ViewResolver : View의 이름을 통해 알맞는 View를 찾는다.

View : 사용자에게 보여질 화면

 

*모듈은 실질적으로 구현이 된 단위, 컴포넌트는 실제 동작하고 있는 엔티티나 활동 중인 독립적 단위. 1개의 서비스를 제공받는 100개의 클라이언트가 있다면 서버 구현 모듈 & 클라이언트 구현 모듈로 모듈은 2개고, 컴포넌트는 101개다.


Spring MVC와 Spring Boot 비교

일단 Spring의 장점은 앞에서 말했듯이 DI를 통해 객체 간 결합도를 낮춰서 유지 보수에 용이하다. 

 

SpringMVC의 단점은 톰캣과 같은 WAS를 별도 설치해야 하고, 이를 해결하는 게 Spring Boot다.

 

* Spring Boot의 장점

- AutoConfiguration을 도입해서 디스패처서블릿 등을 설정하는 시간을 줄여준다.

- 내장 톰캣을 사용하기 때문에 별도의 WAS가 필요 없다.


DTO, VO, DAO, BO란?

  • DTO : Data Trasfer Object로 데이터를 주고받기 위해 사용하는 클래스
  • VO : Value Object로 실제 데이터를 저장하는 클래스
  • DAO : Data Access Object로 DB에 접근해서 실제 데이터를 조회 또는 조작하는 클래스. 예) Repository
  • BO : Business Object로 여러 DAO를 활용해 비즈니스 로직을 처리하는 클래스. 예) Service

리플렉션이란?

리플렉션은 구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드나 변수에 접근할 수 있게 하는 자바 API.

동적으로 클래스를 사용해야 할 때 필요하다. 즉, 작성 시점에는 어떤 클래스를 사용할 지 모르는 상태인데 런타임 시점에 클래스를 가져와 실행해야 할 때 사용된다. 


Spring Security란?

애플리케이션에서 인증 및 권한 부여 방법을 제공하는 데 초점을 맞춘 Spring 프레임워크의 별도 모듈. CSRF 공격과 같은 보안 취약점을 처리한다. 인증과 권한에 대한 부분을 Filter 흐름에 따라 처리한다. 

Filter는 앞 포스팅에서 말했듯이, Dispatcher Servlet으로 가기 전에 적용되어서 가장 먼저 URL 요청을 받고, Interceptor는 Dispatcher와 Controller 사이에 위치한다.

  • 인증 : 해당 사용자가 본인이 맞는지 확인하는 절차
  • 인가 : 인증된 사용자가 요청한 자원에 접근 가능한지를 결정하는 절차

인증을 성공한 뒤 인가를 진행하는데, 이런 절차를 진행하기 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 Credential 기반의 인증 방식을 사용한다.

  • Principal(접근주체) : 보호받는 리소스에 접근하려는 대상
  • Credential(비밀번호) : 리소스에 접근하는 대상의 비밀번호

Spring Security의 주요 모듈

  • SecurityContextHolder : 보안 컨텍스트에 대한 세부 정보를 저장한다.
  • Authentication : 이는 현재 접근하는 주체의 정보와 권한을 담는 인터페이스다.
  • SecurityContext : Authentication을 보관하는 역할로, SecurityContext를 통해 Authentication 객체를 꺼낼 수 있다.
  • UsernamePasswordAuthenticationToken : Authentication을 implements한 AbstractAuthenticationToken의 하위 클래스로, User Id가 Principal의 역할을 하고, Password가 Credential의 역할을 한다. 
  • AuthenticationProvider : 실제 인증에 대한 부분을 처리한다. 인증 전의 Authentication 객체를 받고, 인증이 완료된 객체를 반환한다.
  • AuthenticationManager : 실제 인증 처리는 사실 AuthenticationManager에 있는 AuthenticationProvider에 의해 처리된다. 인증을 성공하면 성공된 Authentication 객체를 생성해서 SecurityContext에 저장하고, 이 인증 상태를 유지하기 위해 세션에 보관한다.
  • UserDetailService : DB에서 User의 정보를 가져오는 서비스.
  • UserDetails : Authentication 객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용된다.

1. 사용자가 아이디 비밀번호를 통해 로그인을 요청 (request)

2. AuthenticationFilter에서 UsernamePasswordAuthenticationToken을 생성해서 AuthenticationManager에 전달

3. AuthenticationManager는 등록된 AuthenticationProvider를 조회해서 인증을 요구

4. AuthenticationProvider는 UserDetailService를 통해 입력받은 아이디에 대한 사용자 정보를 DB에서 조회

5. 입력받은 비밀번호를 암호화해서 DB의 비밀번호와 매칭되는 경우 인증이 성공된 UsernameAuthenticationToken을 생성해서 AuthenticationManager로 반환

6. AuthenticationManager는 Provider로부터 받은 UsernameAuthenticationToken을 다시 AuthenticationFilter로 전달

7. AuthenticationFilter는 전달받은 UsernameAuthenticationToken을 LoginSuccessHandler로 전송해서 토큰을 Response 헤더에 추가해서 반환함.

 

내 코드에서는 CustomUserDetails라는 UserDetailService를 implement하는 서비스를 만들어서 여기서 user정보를 DB로부터 조회한다.

 

인증 전후의 기준은.... AuthenticationProvider가 인증 안된 Authentication을 받아서 인증 완료된 객체로 반환하는데 이때 받은 Authentication에서 getName을 통해 email을 조회했을 때 anonymouseUser인지 확인했었다.


CSRF란?

웹 애플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 해서 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격법


CORS란?

Cross - Origin Resource Sharing (CORS)는 Origin(host)를 가로질러 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 정책이다.

 

예를 들어 www.naver.com 에서 서 api.daum/post/123과 같은 api를 호출했다고 할 때 얻으려는 자원의 출처는 api.daum이다. 현재 출처가 네이버인 상태에서 daum의 api 서버로의 리소스 요청은 브라우저의 sop(same origin policy) 정책에 의해 제한된다. 즉, 현재 요청한 api를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있다는 것이다. 이걸 불러오려면 다른 출처의 리소스를 불러와야 하는건데, 자원을 요청한 출처(네이버)와 해당 요청을 응답하는 서버의 출처(다음)이 다르더라도 해당 자원에 접근할 수 있는 권한을 부여하도록 브라우저에게 알려주는 정책이 CORS다.

728x90
Comments