level2 면접 준비

8 minute read

Spring

  • 경량 컨테이너: java 객체의 라이프사이클을 직접 관리, jar면 설치 완료
  • POJO 기반의 구성
  • DI, IoC 사용
  • AOP 지원: 공통된 기능을 재사용함으로써 모듈화(트랜잭션, 로깅, 보안 등)
  • WAS로부터 독립적인 개발

장점

annotation, 클래스로 설정 파일 대신, rest controller

  • 타 프레임워크에 비해 복잡하지 않음
  • 프로젝트 전체 구조 설계에 유용
  • 다른 프레임워크 포용
  • 개발 생산성과 도구의 지원

[Spring] Bean의 생명주기

spring container -> spring bean -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸 전 콜백 -> 프로그램 종료

[Spring] MVC

Spring MVC는 DispatcherServlet을 기반으로 한 프레임워크로 DispatcherServlet은 handler들에게 요청을 전달하고 수행할 것을 명령한다. view resolver를 통해 렌더링 결과를 반환하기도 한다.
기본적인 handler는 @Controller@RequestMapping을 바탕으로 한다.

  • Exception 처리
    @ControllerAdvice를 통해 @ExceptionHandler로 관리할 exception을 등록해 사용한다.

  • Model
    spring MVC의 model은 Map interface로 client로부터 온 요청에 따라 controller에서 view에 전달되는 것을 의미한다.

    The model (the M in MVC) is a Map interface, which allows for the complete abstraction of the view technology.
    Delegate rendering of response

@RequestMapping, @RequestParam, @ModelAttribute를 통해

  • View
    client에 제공할 model까지 담은, controller로부터 받아오는 페이지, view이다.

  • Controller
    client로부터 들어온 url에 따라 메서드를 mapping받고, model을 붙여서 view에 반환하는 역할을 하는 친구이다.

사용하는 이유

jsp와 servlet 모두 비즈니스 로직과 뷰 호출까지 수행한다. 하지만 각각이 잘하는 일이 존재한다.
서블릿만 이용해도 되지만 view 단을 구현하기 위해 너무 많은 코드가 필요했고 view와 controller 역할의 분리와 간편한 프로그래밍을 위해 등장한 것이 jsp, jsp도 내부에서 servlet 호출

  • jsp: html 코드에 java의 코드를 넣어 web server에서 동적으로 웹 페이지를 생성해 브라우저에 전달하기에 적합, 비즈니스 로직 수행 부적합
  • servlet: html 코드 넣기 부적합, 비즈니스 로직 수행 적합
    따라서 spring mvc는 jsp는 뷰 로직에서만, servlet은 비즈니스 로직인 컨트롤러를 다루도록 만들어진 것이다.
    이 사이에서 view에 비즈니스 로직의 산출물로 전달되는 것이 model이다.

model1, model2

  • model1 사용자의 요청을 jsp가 java bean이나 service를 이용해 전부 처리한다.
    mvc가 분리되어 있지 않아 관리가 어렵다.

  • model2 사용자의 요청을 servlet이 받아 view로 보여줄지 model로 보내줄지 정해서 전송한다.
    view로 가면 jsp가 나온다. mvc가 명확하게 분리되어 있어 확장과 유지보수에 용이하다.
  • 참고

장점

유지보수 편리
코드 중복을 줄일 수 있고 확장성도 매우 높다.

단점

프로젝트가 확장될수록 의존성은 손바닥 뒤집듯 바뀔텐데 스프링은 이 모든 객체 간 의존성을 설계하고 시작해야하다보니 설계가 어렵다
의존 관계가 바뀔 때 해줘야 하는 작업이 너무 크다
성능과의 트레이드오프 존재, 객체지향의 계층 구조 파괴, 객체가 프록시가 됨

[Spring] Core

스프링의 기본이 되는 것으로 IoC, DI 기능을 담당한다. Bean 클래스 제어

IoC와 DI?

제어의 역전으로 프로그램의 흐름이 개발자가 구현한 코드로 흘러가는 것이 아니라 역전되어 흘러가는 것이다.
이 제어의 역전은 대표적으로 framework, 템플릿 메서드 패턴, servlet을 통해 구현될 수 있다.
템플릿 메서드는 부모 클래스에서 대다수의 틀을 구현해두고 자식 클래스에서 호출할 때 자신에게 맞는 인자를 전달하면 부모 클래스가 무슨 값이 들어왔던지 자신의 템플릿을 실행하는 것이다.
일반적으로 프로그램은 main 메서드에서 연쇄적으로 다른 객체를 생성하고 호출하는 일을 통해 진행된다.
하지만 제어의 역전이 일어나면 자신이 사용할 객체를 만들지도, 선택하지도 않는다. 뿐만 아니라 자신도 어디서 어떻게 만들어지는지 알지 못한다.

스프링에서는 DI로 의존성을 주입하는 것을 통해 IoC를 구현하고 있다.
의존성이 주입됨으로써 자신이 어디서 어떻게 생성되고 사용되는지, 자신이 사용하는 객체가 어디서 어떻게 만들어졌는지 알지 못한다.
객체의 생성과 관리 책임은 framework가 맡는다.

[Spring] JDBC

jdbc -> spring jdbc -> jpa의 순서로 추상화가 진행된다.

순수한 jdbc는 connection의 연결, ps, 쿼리 실행, close 등의 작업이 필요하다.
spring jdbc의 경우 datasource가 될 connection 할 벤더만 properties나 Datasource set을 통해 지정해주면 자동으로 연결하고 schema.sql이나 data.sql을 통해 스키마를 생성한다. 이후 직접 쿼리문을 작성해 실행하면 원하는 값을 매핑할 수 있다.
jpa의 경우 객체에 어노테이션만 지정해주면 자동으로 테이블을 생성한다. 또한, repository를 사용하기만 하면 원하는 db와의 작업을 진행할 수 있다.

[Network] Rest API

rest api란 서버에서 제공하는 자원을 uri로, 실행되는 행위를 POST/UPDATE/DELETE/GET과 같은 method로, 그 상태를 status code로 하여 api를 구현하는 방식 중에 하나이다.
언급하는 바와 다르게 실제로는 지켜야할 규약이 많아 구현하기 깐깐하고 어렵다.
하지만 정해진 규칙에 따라 api를 설계할 수 있다는 장점에 따라 많은 개발자들 사이에서 규약이 되어 적용하곤 한다.

[Test] @RestAssured

인수테스트, 통합테스트, end-to-end 테스트로 사용될 수 있는 테스트 방식 중 하나로 메서드에 given, when, then이 있어 상황에 따른 테스트를 주도로 개발하는 bdd 테스트로도 활용되기 적합하다.
하지만 매 테스트마다 @SpringBootTest를 통해 모든 bean을 생성하고 컨테이너에 올려야한다는 단점이 존재한다. 뿐만 아니라, 전체 테스트를 통과하기 위해 @DirtiesContext를 이용해 새롭게 컨테이너를 올리도록 해야해서 느리기도 하고, 성능 쪽으로도 좋지 않은 테스트이다. 이 경우 매번 dirties를 이용해 객체를 재생성하기보다는 drop/delete 후 재생성하는 메서드를 @BeforeEach로 구현하는 것이 좋다.
@SpringBootTest는 실제 SpringBoot 프로젝트가 동작하는 것처럼 webEnvironment에 지정된 포트나 특정 서버로 프로그램을 띄우고 모든 클래스를 돌며 필요한 빈 객체를 생성하고 container를 관리하는 것이다.

[Test] @MockMvc

실제 객체를 통한 테스트가 아닌 가짜 객체를 생성해서 인수테스트, 통합테스트에 사용하는 것으로 빈으로 등록된 객체 선언부에 @MockBean이라는 어노테이션을 달면 비어있는 가짜 객체로 등록된다.
하지만 비어있는 가짜 객체이므로 이 객체를 통한 어떠한 동작이 필요하다면 메서드를 통해 동작을 실행시켜야 한다. 이 부분에서 테스트 대상의 내부 동작을 다 알고 있어야 한다는 단점이 존재한다. 하지만, 가짜이다 보니 매번 컨테이너를 다시 올리고 등록하는 행위를 하지 않아도 되어서 빠르고 비교적 간단히 테스트를 진행할 수 있다.

[Test] 단위테스트와 통합테스트

통합테스트는 독립된 단위가 서로 연결될 때, 예를 들어 서버와 통신이 원활한지, db가 잘 동작하는지 등을 확인하기 위한 테스트이다.
단위테스트는 각 메서드별로 테스트를 진행하는 것을 의미한다.

[Spring] Validation

hadler adapter 내에 message converter에서 들어온 값을 바인딩해주는데 이 과정에서 설정한 어노테이션(@Min, @NotNull, @Pattern)에 맞지 않은 값이 들어온 경우 예외로 잡아서 처리할 수 있다.

[Spring] 동작원리

프로그램이 시작되면 dispatcherServlet이 생성된다. 이와 함께 spring container에 각종 bean들과 requestMapping이 등록된 요청들이 등록된다. client의 요청이 들어오면 filter에서 걸리는 것이 있는지 먼저 확인하고, dispatcherServlet이 해당 요청 url을 보고 handler mapping에 해당 요청이 존재하는지 확인하고 반환한다. 이 과정에서 해당 url이 interceptor가 적용되어야 하는 url이면 인터셉터를 적용해 하고자 하는 행위를 전후에 실행할 수 있다. 이후 매핑에 문제가 없으면 dispatcherServlet이 handler adapter에 컨트롤러를 실행할 것을 요청한다. 이 과정에서 json을 dto 객체로 변환하는 것과 같은 변환 행위가 일어나는데 이 과정에서 valid에 걸리거나, argumentResolver에 걸리면 해당 관련 행위를 먼저 실행한다. 문제가 없으면 controller를 실행한다. restController면 response를 만들어 view resolver에 전달하고, view resolver는 이것을 보고 view를 매핑해 바인딩한다. 그냥 controller의 경우는 model을 넘겨받아 view를 바인딩한다.

[Spring] 세션, 쿠키, 토큰

세가지 모두 stateless한 웹 브라우저의 특성에 따라 상태를 저장하기 위한 방식이다.
쿠키는 크기가 작고 만료일이 존재한다. 속도는 빠르지만 보안이 좋지 않아 오늘 팝업 안보기, 아이디 자동 입력과 같은 경우에 사용된다.
쿠키의 생성과정은 서버에서 쿠키를 생성해 클라이언트에 전송하고 클라이언트는 가지고 있다가 재요청시 쿠키를 함께 전송한다.
세션은 반면에 만료일이 존재하지 않는다. 하지만 server가 리셋되면 브라우저에 저장된 세션도 모두 날라가게 된다. 이것은 쿠키도 마찬가지이다. 주로 로그인을 위해서 사용된다.
세션은 헤더 쿠키에 담겨져 가고 세션이 없으면 서버는 생성해서 클라이언트에 준다.
토큰은 인가를 위해서 사용되는 경우가 많다. 로그인이 진행되면 서버는 만료시간이 있는 토큰을 생성해 클라이언트에 암호화를 진행해 전달한다. 전달된 토큰은 쿠키로 헤더에 저장되고 정해진 시간동안 사용자의 인가에 사용된다. 헤더에 담겨서 전달된 토큰은 복호화를 통해 갖고 있던 header, signature, payload 중에서 payload를 풀어 필요한 정보를 뱉어낼 수 있다. 길이가 길어서 자원이 낭비될 수 있다.

[Spring] API 문서화

swagger와 RestDocs를 사용해 api를 문서화할 수 있다.
스웨거는 적용하기 쉽지만 코드에 변화가 있어야한다는 단점이 있고, 레스트독스는 적용이 어렵지만 모든 테스트가 신뢰할 수 있다는 장점과 코드에 변화가 없어도 된다는 장점이 있다.

[Web] CORS

CORS란 cross origin resouce sharing으로 이름에서 알 수 있다시피 서로 다른 출처에서 자원을 공유할 수 있도록 허용하는 것이다. 애초에 웹 브라우저는 single origin policy로 단일 출처 정책이 적용된다. 하지만 프론트와 백 서버가 다른 경우 cors 문제가 발생하게 된다. 이를 해결하기 위해 cors 설정을 해주어야 하는데 이를 js에서 설정할 수도, 서버에서 설정할 수도 있다.

[infra] 인증과 인가

인증이란, 어떠한 사용자에 대해서 로그인을 해도 되는지 확인하는 것이고, 인가는 확인된 사용자가 어떠한 행위에 접근하고자 할 때 그래도 되는지, 자격이 있는지 확인하는 것이다.
예를 들어 인증이 해당 사람에 대해 출입증을 발급하는 것이라면, 인가는 옳지 않은 사무실에 출입증을 찍고 들어가려고 할 때 방지하고자 함이다.

[infra] public cloud

public cloud란 공용으로 접속할 수 있는 인터넷 모든 공간
자원을 인터넷을 통해 관리할 뿐만 아니라 어떻게 관리할지 cloud 제공 업체에 맡기고 우리는 데이터를 어떻게 얻을지, 저장할지만 고민하도록 하는 것이다.

[Network] TCP/IP

OSI 7계층이 실질적으로 사용되는 것으로 4개의 계층으로 나누어져 있다. 표현, 전송, 네트워크, 링크 계층으로 나누어져 있는데 다양한 프로토콜의 집합으로 네트워크를 동작시킨다.
OSI 7계층이란 클라이언트와 서버간 데이터 전송이 필요할 때 0과 1만을 아는 컴퓨터가 전송하기에 어려움이 있기 때문에 계층을 거치며 데이터를 0과 1로 쪼개어 전공하고자 하는 것이다.
계층을 지날수록 헤더가 붙거나 떨어지는 과정을 통해 데이터와 주소가 알맞게 전송된다.

  • TCP: 신뢰가 되는 데이터 전송 방식으로 udp라는 전송 방식과 다르게 전송에 실패하면 다시 전송하는 방식을 사용한다.
    tcp가 신뢰를 얻는 방식은 확실한 연결을 통해 데이터를 전송한다는 것이다.
    3 way로 연결하고, 원하는 데이터를 전송하고, 4 way로 연결을 해제하는 방식으로 진행된다.

  • IP는 논리적인 주소로 0과 1의 비트를 10진수나 16진수로 변환해 전송할 주소를 만든다.

[Network] bastion 서버

통신을 담당하는 22번 포트에 장애가 발생하면 대처가 불가능하다. 그렇다고 모든 서버에 보안 관련 설정을 해두기는 번거롭고 낭비일 뿐만 아니라 확장에도 어려움이 있다.
서버의 운영을 모니터할 수 있는 오토 스케일링이라는 기술에는 그 수가 정해져있기 때문에 확장 시 적용이 어렵다.
이때 총알받이가 되어줄 배스천 서버를 앞단에 설정하고 배스천 서버를 통해서 서버에 접근할 수 있도록 한다. 이렇게 하면 보안에도 효과적이고 관리에도 효과적인 구성이 된다.
운영 관련 지표와 관리자 트래픽이 구분되어 좋다.

[Network] 서버 통신 과정

naver -> dns로부터 ip주소 얻어온다 -> tcp/ip를 지나 데이터 전송 -> 서버 데이터 수신 -> 서버에서 바인딩할 데이터 전송 -> tcp/ip를 지나 데이터를 얻어 사용자 모니터에 화면 바인딩

[Network] TLS

Tranfer Layser Security로 전송 계층에서 보안을 설정하는 것을 이야기한다. SSl이라고 웹 사이트와 브라우저 간 데이터를 암호화하여 유지하는 기술을 사용한다.
패킷 스니핑을 하면 전송계층에서 보내지는 패킷이 무엇인지 볼 수 있는데 tcp/ip는 이 데이터가 평문이라 중요한 정보를 탈취하기 쉽다.
이를 피하기 위해 tls라는 설정을 사용해 데이터를 암호화한다.
tls는 데이터를 암호화하여 주고받는다. 이 과정에서 클라이언트와 서버 간의 인증이 유효한지, 세션키가 존재하는지 등의 확인을 handshake로 하는 과정이 존재한다.

이렇게 설정된 tls와 같이 비즈니스 로직이 아닌 과정에서 문제를 일으키고 싶지 않은 경우 reverse proxy를 사용한다. 대표적으로 nginx와 같은 기술로 구현되는 리버스 프록시는 지역끼리 연결된 것을 wan으로 관리되도록 도와주는 포워드 프록시와 다르게 wan을 lan으로 옳겨준다.
사용자가 접근하면 자신과 lan으로 연결된 비즈니스 로직에 요청을 전송하는데 이 과정에서 tls가 적용되어 암호화 된 것이 proxy로, 프록시에서 그 암호를 풀어 비즈니스 로직으로 전송하는 과정이 이루어진다.
포워드 프록시는 여러 클라이언트에 대해 적용되고, 리버스 프록시는 여러 서버에 대해 적용된다.
리버스 프록시를 통해 보안성, 성능, 확장성 등이 상승될 수 있다.

공개키를 보내고 인증을 받으면 공유키로 http 전송을 하도록 하는 것

[Network] load balancer

서버에 접근하는 작업량을 특정 알고리즘에 의해 분산시켜주는 것이다.
l4, l7이 존재하는데 전송계층, 표현 계층에서 적용되는 차이가 있다.

servlet
spring mvc http 요청