Java

Java 면접(인터뷰) 스터디 회고 3

리콜 2024. 11. 21. 07:49

13. Spring 에서 Interceptor와 Servlet Filter에 대해 설명해 주세요.

Filter는 Dispatcher Servlet 에 요청이 전달되기 전후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공합니다. Dispatcher Servlet은 스프링 제일 앞에 존재하는데 따라서 Filter는 SPring외부에 존재합니다.

스프링 컨테이너가 아닌 톰캣과 같은 서블릿 컨테이너에 의해 관리,

스프링 빈으로 등록은 된다.

Intercepter는 Dispatcher 가 컨트롤러를 호출하기 전과 후에 응답을 참조하거나 가공할 수 있는 기능을 가지고 있다. 즉 스프링 내부에 동작한다.

설명만 들어보면 인터셉터만 쓰는게 나아보이는데, 아닌가요? 필터는 어떤 상황에 사용 해야 하나요?

관리 되는 영역이 다르기때문에 인터셉터는 스프링에 의한 예외처리가 된다는 장점이 있지만 필터는 Request나 Response를 조작할수 있다는 Intercepter에는 없는 기능도 있습니다.

필터는 스프링과 무관하게 전역적으로 처리해야하는 작업들에 적용할 수 있습니다. 대표적으로 공통된 인증/ 인가 작업 , 이미지 인코딩, Spring과 분리되어야하는 기능에 필요합니다.

인터셉터는 API호출에대한 로깅검사나, 세부적인 보안 및 인증/인가 공통작업등에 사용할 수 있습니다.

  • 필터는 스프링에 접근할 수없는데 빈으로는 등록 되는데 스프링은 필터에 접근할 수 있냐

14. DispatcherServlet 의 역할에 대해 설명해 주세요.

dispatch라는 보내다는 의미와 같이 HTTP 프로토콜로 들어오는 모든 요청을 가정 먼저 받아 적합한 컨트롤러에 보내주는 Front Controller이다.

클라이언트로 부터 어떠한 요청이 오게 되면 모든 요청을 자신이 먼저 받고 이러한 요청들을 세부 컨트롤러에게 전달하는 역할

여러 요청이 들어 온다고 가정할 때, DispatcherServlet은 한번에 여러 요청을 모두 받을 수 있나요?

Tomcat과 같은 서블릿 컨테이너가 클라이언트로부터 들어오는 요청을 처리하기 위해 스레드 풀 사용

요청 들어오면 스레드 풀에서 사용가능한 스레드를 하나 할당하여 해당 요청을 처리합니다.

  • 수많은 @Controller 를 DispatcherServlet은 어떻게 구분 할까요?
    1. 요청 정보를 보고 Servlet WebApplicationContext 안에서 HandlerMapping을 통해 요청을 위임할 컨트롤러를 검색해 찾는다.
    2. 찾은 컨트롤러로 요청을 위임할 HandlerAdapter를 찾는다.
    3. HandlerAdapter가 컨트롤러로 요청(HttpRequest)을 위임한다
      1. Argument Resolver가 파라미터를 처리해 컨트롤러로 보낸다.
    4. 컨트롤러는 Root WebApplicationContext 속 Service, Repository… 등을 호출해가며 비즈니스 로직을 처리한다.
    5. 컨트롤러 메소드에서 최종적인 반환값(Response Entity)이 리턴된다.
    6. 핸들러 어댑터 리턴값을 ViewResolver에 전달한다.
    7. ViewResolver가 View를 검색하고 찾은 View에 응답을 전달한다.
    8. 디스패처 서블릿에서 View로부터 받은 응답을 클라이언트(프론트 서버)로 반환해준다!

뷰 리졸버 왜 만들어졌나

컨트롤러와 뷰의 분리: 컨트롤러는 비즈니스 로직에 집중하고, 뷰는 화면 표현에만 집중할 수 있도록 역할을 분리합니다 유연성: 다양한 뷰 기술(JSP, Thymeleaf, FreeMarker 등)을 사용할 수 있도록 유연한 환경을 제공합니다.

15. JPA와 같은 ORM을 사용하는 이유가 무엇인가요?

JPA를 사용하면 SQL중심적 개발에서 객체 중심적인 개발에 집중할 수 있습니다. 기존에는 필드를 변경하면 모든 SQL문을 찾아가면서 변경해야 했지만 JPA를 사용하면 필드만 추가하면 JPA가 처리해줘 유지보수가 쉬워집니다.

영속성은 어떤 기능을 하나요? 이게 진짜 성능 향상에 큰 도움이 되나요?

  • 우선 영속성은 엔티티를 영구 저장하는 환경으로서 객체를 보관하는 가상의 데이터 베이스 같은 역할을 수행합니다.유지보수성 향상: 객체 모델과 데이터베이스 구조를 일치시켜 코드 가독성을 높이고 유지보수를 용이하게 합니다.
  • 엔티티: 데이터베이스 테이블과 매핑되는 자바 객체입니다.
  • 엔티티 매니저 : 엔티티의 구현체를 생명주기를 관리해준다.
    Entity 객체를 영속성 콘텍스트(persistence context)에 저장하여 관리한다.
    즉, Entity와 Persistence Context 사이에 존재하는 역할이다.

  • 영속성 컨텍스트: 엔티티를 관리하는 메모리 공간으로, 애플리케이션과 데이터베이스 사이의 중간 매개체 역할을 합니다.
  • 개발 편의성: 복잡한 SQL 쿼리를 직접 작성할 필요 없이, 객체 지향적인 방법으로 데이터베이스를 조작할 수 있습니다.
  • 생산성 향상: 객체 지향적인 방식으로 데이터베이스를 다룰 수 있어 개발 생산성을 높입니다.
    • 영속 상태: 영속성 컨텍스트에 관리되는 엔티티의 상태입니다. 영속 상태의 엔티티는 변경 사항이 발생하면 자동으로 데이터베이스에 반영됩니다.
    • 준영속 상태: 영속성 컨텍스트에서 분리된 엔티티의 상태입니다. 더 이상 영속성 컨텍스트에 의해 관리되지 않습니다.
    • 비영속 상태: 아직 영속성 컨텍스트에 저장되지 않은 엔티티의 상태입니다.엔티티의 생명주기
  • 엔티티 매니저
    • Entity를 영속성 컨텍스트에 등록하면 1차캐시에 등록이 된다.
    • 영속성 컨택스트 내부에 1차 캐시 라는 것이 있습니다. 데이터 베이스의 기본키를 식별자 값으로 갖고 값은 엔티티 인스턴스로가져 이를 사용하여 조회 하게 됩니다. 이러한 캐싱으로 데이터베이스 접근을 최소화할 수 있습니다.
    • 하지만 1차 캐시가 있는 EntityManager는 트랜잭션 단위로 만들고 사라진다. 즉, 1차 캐시가 살아있는 시간은 매우 짧아 성능에 큰 효과는 없다.
    • 2차캐시 : 애플리케이션 전체가 공유하는 캐시
    • 영속된 Entity의 동일성 보장 : 하나의 트랜잭션 동안 동일한 객체를 여러번 조회하면 이를 같은 값으로 처리,
         User a = em.find(userA);
          User b = em.find(userA);
          System.out.println(a == b); // true 반환
    
    원래는 다른 주소 값이지만동일한 sql반복해서 수행하면 db로 부터 값 조회하지 않고 1차 캐시에서 조회
  • jpa는 조회되는 동일한 객체에 대해서 같은 객체로 처리
  • 지연 로딩 : 엔티티 DB에서 가져올때 만약 연관관계를 가진 다른 객체를 가지고 있다면 연관된 객체도 함께 DB에서 조회, 프록시 객체로 가져온다.
  • 쓰기 지연 : 한 트랜잭션 안에서 DB에 보낼 쿼리문을 모았다가 한번에 보내어 네트워크 부하를 줄여주기 위한 기능입니다. commit()하기 전가지 sql작성하지않는다.

N + 1 문제에 대해 설명해 주세요.

  • N + 1문제는 이해하기 쉽게 설명하자면 1 + N 문제라고 이야기 할 수 있습니다. 1개의 요청 쿼리로 처리 되길 기대했는데 N개의 추가 쿼리가 발생하는 상황입니다.
  • 연관 관계에서 발생하는 이슈로 연관관계가 설정된 엔티티를 조회할 경우에 조회된 데이터 갯수만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽으면서 발생하는 문제
  • 해결방법으로는 Fetch Join이 있습니다. 연관된 엔티티나 컬렉션을 한번에 조회해서 영속성 컨텍스트에 전부 올려버립니다. 즉 한꺼번에 가져오는 기능입니다. 한번에 가져와 객체화를 해주어 DB를 거치지 않고 데이터 꺼내서 반환해줍니다.

즉시 로딩과 fetch join의 차이?

즉시로딩은 연관된 엔티티를 조회 할때, 부모 엔티티를 조회하는 SQL 문과 함께 자식 엔티티를 조회하는 SQL문이 별도로 실행되는 방식

다른 해결 방법들

  • 지연로딩때 batch사이즈 설정 ( n을 줄여준다.)
  • fetch join은 inner join이고 entity graph이라는 방법도 존재하는데 이는 outer join의 방식을 사용한다.

Fetch Join 은 부모 엔티티를 조회 할때 JOIN문을 사용하여 자식 엔티티를 조회하는 방식, SQL문이 복잡해 질 수 있으며 성능 향상을 위해 적절한 조건을 설정해야합니다.

Fetch Join을 사용하면 N + 1문제를 효과적으로 해결 할 수있지만 조건을 잘못 설정한다면 N+1문제가 발생 할 수 있다.

 

지연 로딩과의 혼용:

  • Fetch Join을 설정한 연관 관계에 대해 지연 로딩을 추가로 설정하면, Fetch Join의 효과가 상쇄될 수 있습니다.
  • 예시: 부모 엔티티를 Fetch Join으로 가져오면서 자식 엔티티는 지연 로딩으로 설정한 경우, 자식 엔티티에 접근할 때마다 추가 쿼리가 발생할 수 있습니다.

컬렉션의 반복 처리:

  • Fetch Join으로 가져온 컬렉션을 반복 처리하면서 각 요소에 대한 추가 쿼리를 실행하는 경우 N+1 문제가 발생할 수 있습니다.
  • 예시: 부모 엔티티의 자식 컬렉션을 반복하면서 각 자식 엔티티의 연관된 다른 엔티티를 조회하는 경우입니다.

따라서 Fetch Join 전략을 잘짜야하고, 불필요한 데이터를 미리 로딩하지 않아야 한다.

 

16. @Transactional 은 어떤 기능을 하나요?

선언적 트랜잭션으로 소스코드에 트랜잭션 관련 로직을 넣어두지 않고 비지니스 로직에서 완전히 분리하는 방식

프로그래밍에 의한 트랙잭션에서 나온 단점인 트랜잭션 코드 중복 문제, 소스코드 유지보수의 문제 해결 가능.

트랜잭션이라는 횡단 관심사를 비지니스 로직에서 완전히 부닐하기 때문에 SRP관점에서 봤을때도 적합하고 많은 양의 트랜잭션로직을 적용하기에도 합리적이다.

@Transactional을 메소드 또는 클래스에 명시하면 AOP를 통해 Target이 상속하고 있는 인터페이스 또는 Target객체를 상속한 Proxy 객체가 생성되며, Proxy 객체의 매소드를 호출하면 Targe메소드 전 후 로 트랜잭션 처리를 수행한다.

@Transactional(readonly=true) 는 어떤 기능인가요? 이게 도움이 되나요?

  • readonly 속성을 통해 트랜잭션을 읽기 전용으로 설정할 수 있다.
  • 영속성 컨텍스트는 Entity 조회 시 초기 상태에 대한 Snapshot(1차 캐시 내부에 존재)을 저장한다.
    • 왜 스냅샷을 사용하는가?
      • 효율적인 변경 감지: 스냅샷을 저장해 두면, 엔티티의 모든 속성을 일일이 비교할 필요 없이 변경된 속성만 확인할 수 있습니다.
      • 데이터 일관성 유지: 트랜잭션 내에서 발생한 모든 변경 사항이 일괄적으로 처리되므로 데이터베이스의 일관성을 유지할 수 있습니다.
  • 트랜잭션이 Commit 될 때, 초기 상태의 정보를 가지는 Snapshot과 Entity의 상태를 비교하여 변경된 내용에 대해 update query를 생성해 쓰기 지연 저장소에 저장한다.
  • 그 후, 일괄적으로 쓰기 지연 저장소에 저장되어 있는 SQL query를 flush 하고 데이터베이스의 트랜잭션을 Commit 함으로써 우리가 update와 같은 메서드를 사용하지 않고도 Entity의 수정이 이루어진다. 이를 변경 감지(Dirty Checking) 라고 한다.
    • 더티 체킹
      1. 엔티티 수정: 개발자가 엔티티의 속성 값을 변경합니다.
      2. 스냅샷 비교: JPA는 변경된 엔티티를 감지하고, 스냅샷과 비교하여 값이 변경되었는지 확인합니다.
      3. 변경 감지: 만약 값이 변경되었다면, 해당 엔티티는 "더티" 상태로 표시됩니다.
      4. 트랜잭션 커밋: 트랜잭션이 커밋될 때, JPA는 더티 상태인 모든 엔티티에 대한 UPDATE SQL을 생성하고 데이터베이스에 반영합니다.
      더티 체킹의 장점
      • 개발 편의성: 개발자가 수동으로 UPDATE SQL을 작성할 필요가 없습니다.
      • 데이터 일관성: 트랜잭션의 일관성을 보장합니다.
      더티 체킹의 단점
      • 성능 오버헤드: 많은 엔티티를 관리하는 경우, 스냅샷 비교에 따른 성능 오버헤드가 발생할 수 있습니다.
      • 복잡한 객체 관계: 양방향 연관 관계나 상속 관계가 복잡한 경우, 더티 체킹 로직이 복잡해질 수 있습니다.
    • 더티 체킹 과정
  • 이때 readonly를 설정하게 된다면 스프링 프레임 워크가 JPA 세션 플러시 모드는 Manul로 설정하게 되어 수동으로 flush를 호출하지 않으면 flush가 수행되지않는다
  • 따라서 조회용 데이터에 예상치 못한 수정을 방지 할 수 있다.
  • 또한 변경감지를 위한 SnapShot을 따로 보관하지 않아 메모리상 이점 을 얻을 수 잇다.

그런데, 읽기에 트랜잭션을 걸 필요가 있나요? @Transactional을 안 붙이면 되는거 아닐까요?

  • 일관성 유지 : 다른 트랜잭션에서 데이터를 수정중 일대에도 조회작업이동시에 실행되면 수정이 완료되기 전의 데이터를 읽을 수 있다. 따라서 조회작업에도 트랜잭션을 적용
  • 로드 밸런싱 : 특정작업이 많은 시간이 걸리는 경우 , 다수의 작업이 해당작업을참조하는 경우가 발생할 수 잇다. 이때 트랜잭션을 걸어 작업이 완료될때까지 조회 작업을 블록하여 일관된 데이터를 제공할 수 있다.
  • https://hungseong.tistory.com/74
 

@Transactional(readOnly = true)를 왜 붙여야 하나요

스프링으로 개발하면서 필연적으로 사용하게 되는 @Transactional. 우리는 스프링의 AOP를 통해 @Transactional 어노테이션만으로 손쉽게 Service Layer에서 트랜잭션을 걸 수 있다. 일반적으로, 조회용 메서

hungseong.tistory.com

 

17. Java 에서 Annotation 은 어떤 기능을 하나요?

자바 1.5버전 이상에서 부터 사용가능한 클래스 파일에 임베드 되어 컴파일러에 의해 생성된 이후 JVM에 포함되어 동작, anootation이 나오기 전에는 xml 및 마커 인터페이스를 통해 추가적인 정보를 제공 할 수 있엇다.

코드 가독성이 좋아진다. : 클래스 메서드 필드 등 코드와 가까이 있어 코드의 설정을 한눈에 읽기 좋다.

설정의 간소화 : 별도의 설정 파일 작성없이 어노테이션 적용을 통해 설정 간소화

중복 코드 제거 : 공통적인 코드 패턴이나 설정을 재사용하여 코드 중복을 줄이고 효율적

프로세서를 통한 검증과 코드 생성 : 어노테이션 프로세서를 이용해 컴파일 시점에 어노테이션을 처리하고 검증 할 수 있다.

컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공

소프트웨어 개발 툴이 빌드나 배치시 코드를 자동으로 생성할 수 있도록 정보를 제공

실행시 특정기능을 실행하도록 정보를 제공

단점 : 런타임 시점에 리플렉션을 사용하여 처리하는 어노테이션의 경우 성능상의 오버헤드가 발생할 수 있다. 어노테이션도 컴파일 시점에 오류를 확인할 수 있지만, 어노테이션 로직이 런타임에 에러를 발생시키거나 어노테이션에 잘못된 값이 할당된 경우 컴파일 시점에 오류를 확인할 수 없을 수도 있다.

별 기능이 없는 것 같은데, 어떻게 Spring 에서는 Annotation 이 그렇게 많은 기능을 하는 걸까요?

  • 어노테이션의 장점을 바탕으로 생각해본다면 xml을 통한 복잡한 설정으로 인해 코드의 복잡성이 올라가게 되고 이는 가독성을 떨어뜨리고 유지보수가 어려워진다.
  • 가독성, 유지보수 간결함, 표준화 등 측면의 장점, 효율적이고 명확한 코드 작성을 할 수 있다.

Lombok의 @Data를 잘 사용하지 않는 이유는 무엇일까요?

  • Setter의 남용 : id의 필드가 변경을 허용치 않기로 했다면 setter도 없어야하는데 Data를 사용하게 된면 id필드도 setter가 생성되기 때문에 안정성을 보장 받을 수 없게 된다.
  • @RequiredArgsConsturctor 로 인해서 인스턴스 멤버 의 순서를 바꾸게 되었을때 lombok이 개발자도 모르게 생성자 파라미터 순서를 필드 순서에 따라 변형, IDE도 클래스가 바뀐건 없다고 인식하기 때문에 아무런 문제 없어 보이지만 실제로 입력된 값이 바뀌어 들어가는 상황이 발생할 수 있다.
  • ToString() 순환 참조문제, Car라는 클래스에 Person이라는 클래스가 있고, Person이라는 클래스에 Car라는 클래스가 있으면 Car을 ToString하려할때 Person이라는 필드의 ToString이 호출, 다시 Person안에서 Car필드 ToString을 호출하면서 순환 참조 문제가 발생한다.

18. Tomcat이 정확히 어떤 역할을 하는 도구인가요?

정적 콘텐츠를 요청하면 웹 서버에서 바로 제공한다.

동적 콘텐츠를 요청하면 WAS로 넘겨서 처리한다.

즉 정적 콘텐츠는 웹 서버가 담당하도록, 동적 콘텐츠는 WAS가 담당하도록 분리시킨 것.

자바의 서블릿, JSP를 실행하도록 돕는 웹 어플리케이션 서버 WAS

(아파치 http서버는 웹서버, 정적 컨텐츠를 제공)

톰캣은 웹서버 + was 역할 모두함

Connector라는 컴포넌트를 통해서 HTTP요청을 직접 받을 수 있다. 요청을 받아 웹컨테이너로 넘겨주고 웹컨테이너에서 데이터를 처리 응답을 웹서버로 넘겨준다.

혹시 Netty에 대해 들어보셨나요? 왜 이런 것을 사용할까요?

비동기 이벤트 기반 네트워크 애플리케이션 프레임 워크로서 유지보수를 고려한 고성능 프론토콜 서버와 클라이언트를 빠르게 개발 가능

네티가 이벤트를 사용하여 데이터를 처리해주기 때문에 순수 자바코드로잔 네트워크 프로그램보다 훨씬 쉽게 개발가능

반응형

'Java' 카테고리의 다른 글

CS 스터디 회고 - 운영체제 1  (0) 2024.12.01
CS 스터디 회고 - java 2  (0) 2024.11.15
[CS 스터디 회고] JAVA 면접 질문 대비  (1) 2024.11.08
JAVA JVM Memory 정리  (1) 2024.07.08
Java priority queue  (0) 2023.09.30