1. Spring이 뭔가요?
- Spring은 Java 기반의 오픈 소스 프레임워크로, 엔터프라이즈 애플리케이션을 개발하기 위한 다양한 기능과 도구를 제공합니다. 주요 기능으로는 의존성 주입(Dependency Injection), AOP(Aspect-Oriented Programming), 트랜잭션 관리, 데이터 액세스 추상화, MVC 웹 프레임워크 등이 있습니다.
2. Spring MVC 구조를 설명해보세요.
- Spring MVC는
Model
,View
,Controller
의 구조로 이루어져 있습니다.
Model
: 비즈니스 로직과 데이터 처리를 담당하는 부분입니다.
View
: 사용자 인터페이스를 표현하는 부분으로 클라이언트에게 결과를 전송합니다.
Controller
: 클라이언트의 요청을 받아 해당 요청을 처리하고 Model과 View를 연결하는 역할을 합니다.
3. Spring에서 Filter와 Interceptor의 차이점은 무엇인가요?
Filter
는 서블릿 컨테이너에서 요청과 응답에 대한 전체적인 처리를 담당하는데, Spring과 무관하게 동작합니다.Interceptor
는 Spring MVC에서만 동작하며 컨트롤러 호출 전후에 특정한 로직을 수행할 수 있습니다. Filter는 요청과 응답을 수정할 수 있지만 Interceptor는 컨트롤러에서 처리되는 요청과 응답에만 영향을 미칩니다.
4. AOP가 무엇인가요?
AOP(Aspect-Oriented Programming)
는 프로그램의 흐름과는 별도로 관심사(Aspect)를 모듈화하여 코드의 재사용성과 유지보수성을 향상시키는 프로그래밍 패러다임입니다. AOP는 주로 로깅, 트랜잭션 관리, 보안 등과 같은 부가적인 관심사를 분리하여 모듈화할 때 사용됩니다.
5. 쓰레드는 무엇인가요?
쓰레드(Thread)
는 프로세스 내에서 실행되는 독립적인 실행 흐름을 나타냅니다. 여러 쓰레드가 하나의 프로세스 내에서 동작하며, 각 쓰레드는 자신만의 스택을 가지고 동작합니다. 쓰레드를 사용하면 다중 작업을 동시에 수행할 수 있으며, 자원 공유와 병렬 처리가 가능해집니다.
6. 불변 클래스가 무엇이고 예시가 뭐가 있나요?
불변 클래스(Immutable Class)
는 한 번 생성되면 내부 상태가 변경되지 않는 클래스를 의미합니다. 예시로는 Java의 String 클래스와 java.time.LocalDate 클래스가 있습니다. 이러한 클래스는 객체를 생성한 후에는 내부 데이터를 변경할 수 없으며, 스레드 안전하고 예측 가능한 동작을 제공합니다.
7. 예외 처리를 try-catch로 처리하는데 공통으로 처리하고 싶습니다. 어떻게 하면 될까요?
- 예외 처리를 공통으로 처리하려면 예외 처리를 중복해서 작성하지 말고 예외 처리기를 사용하세요. Spring에서는
@ControllerAdvice
어노테이션을 사용한 클래스를 만들고,@ExceptionHandler
어노테이션을 사용하여 예외 처리 메소드를 정의할 수 있습니다. 이러한 클래스를 통해 애플리케이션 전체의 예외를 일관되게 처리할 수 있습니다.
8. 사용자가 브라우저를 통해서 서버에 요청하는 전체 flow를 설명해주세요.
- 브라우저에서 URL을 입력하거나 링크를 클릭합니다.
- 브라우저는 DNS(Domain Name System) 서버를 통해 요청한 도메인 이름을 IP 주소로 변환합니다.
- 브라우저는 HTTP 요청 메시지를 생성하고 해당 서버의 IP 주소와 포트 번호로 전송합니다.
- 서버는 요청을 받아서 웹 애플리케이션 서버(예: Tomcat)에 전달합니다.
- 웹 애플리케이션 서버는 요청을 처리하고, 필요한 데이터베이스나 다른 서비스와 통신하여 데이터를 가져옵니다.
- 서버는 HTTP 응답 메시지를 생성하고 브라우저로 전송합니다.
- 브라우저는 응답을 받아서 HTML, CSS, JavaScript 등을 렌더링하여 화면에 표시합니다.
9. Web Server와 Web Application Server의 차이에 대해서 설명해주세요.
Web Server
는 HTTP 프로토콜을 사용하여 클라이언트로부터 요청을 받고, 정적인 웹 페이지(HTML, 이미지 등)를 제공하는 서버입니다. 대표적으로 Apache, Nginx 등이 있습니다.Web Application Server
는 동적인 웹 애플리케이션을 실행하기 위한 환경을 제공하는 서버입니다. 서블릿 컨테이너와 같은 기능을 제공하며, Java EE(Enterprise Edition)나 Spring과 같은 프레임워크를 사용하여 웹 애플리케이션을 개발하고 배포하는 데 사용됩니다. Web Application Server는 서블릿 컨테이너, JSP 컨테이너, 데이터베이스 연동 등의 기능을 제공하여 동적인 웹 애플리케이션을 처리할 수 있습니다.
10. HTTP와 HTTPS의 차이에 대해서 설명해주세요.
HTTP(Hypertext Transfer Protocol)
는 웹 서버와 클라이언트 간의 텍스트 데이터를 주고받는 프로토콜입니다. 데이터 전송 시 암호화되지 않기 때문에 보안성이 낮습니다.HTTPS
는 HTTP의 보안 버전으로, 데이터를 암호화하여 전송합니다. SSL 또는 TLS 프로토콜을 사용하여 데이터의 안전성을 보장하며, 주로 민감한 정보(예: 로그인 정보, 결제 정보)를 주고받을 때 사용됩니다.
11. 각 라인의 결과 및 이유를 설명하시오.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
System.out.println(new Object() == new Object());
// 결과: false
// 이유: 새로운 Object 인스턴스를 두 번 생성하면 각각 다른 객체가 되므로 == 연산자로 비교하면 false가 반환됩니다.
System.out.println(new String("a") == new String("a"));
// 결과: false
// 이유: 문자열 리터럴 "a"는 문자열 풀(String Pool)에 저장되고, new String()으로 생성된 문자열은 풀에 저장된 문자열과는 다른 객체가 되므로 false가 반환됩니다.
System.out.println("a" == new String("a"));
// 결과: false
// 이유: 문자열 리터럴 "a"와 new String()으로 생성된 문자열은 서로 다른 객체이므로 false가 반환됩니다.
System.out.println("a".equals(new String("a")));
// 결과: true
// 이유: 문자열 리터럴 "a"와 new String()으로 생성된 문자열은 내용이 동일하므로 equals() 메소드로 비교하면 true가 반환됩니다.
System.out.println("a" == "a");
// 결과: true
// 이유: 문자열 리터럴 "a"는 문자열 풀에 한 번 저장되고, 두 개의 "a" 리터럴은 동일한 객체를 참조하므로 true가 반환됩니다.
12. JVM이란 무엇인가요?
JVM(Java Virtual Machine)
은 Java 프로그램을 실행하는 가상 머신입니다. Java 언어로 작성된 소스 코드는 컴파일러에 의해 바이트 코드로 변환되며, JVM은 이 바이트 코드를 실행하여 프로그램을 실행시킵니다. JVM은 메모리 관리, 가비지 컬렉션, 스레드 관리 등을 담당하여 Java 프로그램의 효율적인 실행을 지원합니다.
13. Interface와 Abstract Class의 차이는?
Interface
와Abstract Class
는 모두 추상화를 제공하는데 사용됩니다.Interface
: 모든 메소드가 추상 메소드이며, 구현을 포함하지 않습니다. 다중 상속을 지원하며, 클래스가 여러 인터페이스를 구현할 수 있습니다. 인터페이스끼리 다중 상속할 수 있습니다.Abstract Class
: 추상 메소드 뿐만 아니라 구현된 메소드도 가질 수 있습니다. 단일 상속만 지원합니다. 인스턴스 생성이 불가능하며, 하위 클래스에서 상속하여 사용합니다.
14. Marker Interface란?
Marker Interface
는 메소드나 필드를 정의하지 않고, 해당 인터페이스를 구현한 클래스에 어떤 특정한 행동 또는 상태를 나타내는 표식을 부여하기 위해 사용됩니다. 예를 들어, Java의 Serializable 인터페이스는 객체를 직렬화할 수 있다는 것을 나타내는 마커 인터페이스입니다.
15. java.lang.Object가 존재하는 이유는?
java.lang.Object
클래스는 모든 Java 클래스의 최상위 클래스이며, Java 언어의 기본적인 기능을 제공합니다. 이 클래스는 다음과 같은 이유로 존재합니다- 모든 객체는 Object 클래스의 하위 클래스이므로 다형성을 지원합니다.
- 객체의 기본적인 메소드인 equals(), hashCode(), toString()을 제공합니다.
- 객체의 락(Lock)을 관리하기 위한 wait(), notify(), notifyAll() 메소드를 제공하여 스레드 동기화를 지원합니다.
16. Design Pattern이란 무엇이고, 알고 있는 패턴을 설명하시오.
Design Pattern
은 소프트웨어 디자인에서 자주 발생하는 문제를 해결하기 위한 일련의 설계 모범 사례들의 집합입니다. 여러 개발자들 사이에서 공통적으로 사용되는 디자인 패턴은 소프트웨어의 구조를 개선하고 유지보수성을 향상시킵니다. 몇 가지 대표적인 디자인 패턴은 다음과 같습니다.Singleton Pattern
: 오직 하나의 인스턴스만 생성하도록 보장하는 패턴.Factory Method Pattern
: 객체 생성을 서브 클래스에 위임하여 유연한 객체 생성을 지원하는 패턴.Observer Pattern
: 객체 간의 일대다 다른 객체의 상태 변경을 관찰하고 통지하는 패턴.Strategy Pattern
: 알고리즘을 캡슐화하고 동적으로 교체할 수 있는 패턴.MVC (Model-View-Controller) Pattern
: 사용자 인터페이스를 모델, 뷰, 컨트롤러로 분리하여 관리하는 패턴.Decorator Pattern
: 객체에 동적으로 기능을 추가하거나 확장하는 패턴.Composite Pattern
: 객체들을 트리 구조로 구성하여 단일 객체처럼 다루는 패턴.Adapter Pattern
: 인터페이스를 다른 인터페이스로 변환하여 호환성을 제공하는 패턴.Proxy Pattern
: 다른 객체에 대한 대리자를 제공하여 접근 제어나 추가 동작을 수행하는 패턴.
17. synchronized에 대해 설명하시오.
synchronized
는 자바에서 다중 스레드 환경에서의 동기화를 제공하기 위한 키워드입니다. synchronized를 사용하면 한 번에 하나의 스레드만 특정 블록 또는 메소드에 접근할 수 있도록 보장합니다. 이를 통해 공유 자원에 대한 안전한 접근을 보장할 수 있습니다.
18. 함수 정의부에 있는 synchronized와 함수 안에서 사용하는 경우의 차이를 설명하시오.
- 함수 정의부에
synchronized
키워드를 사용하는 경우 해당 함수는 해당 클래스의 모든 인스턴스에 대해 하나의 락을 획득합니다. 따라서 동일한 클래스의 모든 인스턴스에서 해당 함수를 동시에 호출할 때 동기화가 유지됩니다. - 함수 안에서 특정 블록을
synchronized
키워드로 감싸는 경우 해당 블록만 동기화됩니다. 이 블록에서 사용되는 객체에 대한 락을 획득하며, 다른 스레드에서 동시에 해당 블록에 접근하지 못하도록 합니다.
19. volatile이란?
volatile
키워드는 변수를 메인 메모리에 저장하고, 스레드 간의 가시성을 보장하는 역할을 합니다. volatile로 선언된 변수의 값을 읽거나 쓸 때 CPU 캐시가 아닌 메인 메모리에서 직접 읽거나 쓰도록 합니다. 이를 통해 다른 스레드에서 변수의 변경 사항을 즉시 볼 수 있게 됩니다. volatile은 주로 변수의 변경을 다른 스레드에 통지하고, 무한 루프 등에서 변수의 캐싱을 방지하는데 사용됩니다.
20. ThreadLocal이란?
ThreadLocal
은 스레드 별로 고유한 데이터를 관리하기 위한 클래스입니다. 각 스레드는 자신만의 ThreadLocal 변수를 가질 수 있으며, 이 변수에 데이터를 저장하고 검색할 수 있습니다. 주로 스레드 간에 데이터를 공유하지 않고 각 스레드에게 독립적인 데이터를 제공해야 할 때 사용됩니다.
21. Inner Class에서 static이 있는 경우와 없는 경우의 차이는?
- Inner Class 내부에 static 키워드가 있는 경우, 이 내부 클래스는 외부 클래스의 인스턴스와 독립적으로 존재합니다. 따라서 static inner class의 인스턴스를 생성할 때 외부 클래스의 인스턴스와 상관없이 생성할 수 있습니다.
- Inner Class 내부에 static 키워드가 없는 경우, 이 내부 클래스는 외부 클래스의 인스턴스와 연결되며, 외부 클래스의 인스턴스 없이는 내부 클래스의 인스턴스를 생성할 수 없습니다. 이 경우 내부 클래스는 외부 클래스의 멤버에 접근할 수 있습니다.
- Inner Class 내부에 static 키워드를 하지 않으면 객체가 생성되고 GC에서 수거할 때 우선적으로 만들었던 외부클래스가 수거가 되지않아 OutOfMemory에러가 발생 할 수 있으니 주의해야한다.
22. Generic이란?
Generic
은 자바에서 타입 안전성(type safety)을 제공하기 위한 메커니즘입니다. Generic을 사용하면 컬렉션과 같은 자료 구조나 메소드에서 사용되는 데이터의 타입을 컴파일 시에 정의하고 검사할 수 있습니다. 이로써 런타임 에러를 방지하고 코드의 재사용성을 높일 수 있습니다.
23. Exception Hierarchy를 그리고 주요 클래스를 설명하시오.
- Java의 Exception 클래스들은 계층 구조를 가집니다. 가장 상위에는
Throwable
클래스가 있으며, 그 아래에는Error
와Exception
클래스가 있습니다. Error
: 시스템 레벨의 치명적인 오류를 나타냅니다. 프로그램 코드에서 처리할 수 없으며 주로 가상 머신 또는 시스템 환경에 의한 문제를 나타냅니다.Exception
: 일반적인 예외 상황을 처리하는 클래스입니다.Checked Exception
: 컴파일러가 강제로 예외 처리 코드를 작성하도록 요구하는 예외들입니다. IOException, SQLException 등이 여기에 속합니다.Unchecked Exception
(Runtime Exception): 컴파일러가 강제로 예외 처리 코드를 작성할 필요가 없는 예외들입니다. NullPointerException, ArrayIndexOutOfBoundsException 등이 여기에 속합니다.
24. Immutable Class(불변 클래스)란?
Immutable Class
는 객체가 한 번 생성되면 내부 상태를 변경할 수 없는 클래스를 말합니다. 불변 클래스는 다음과 같은 특징을 가집니다:- 내부 상태는 객체 생성 시 초기화되며 그 이후에 변경되지 않습니다.
- 불변 클래스의 객체는 다중 스레드 환경에서 안전하게 공유될 수 있습니다.
- 객체의 상태가 변경되지 않기 때문에 복사본을 만들 필요가 없어 메모리 사용을 줄일 수 있습니다.
- 자주 사용되는 해시 맵 키(key)나 집합(set) 요소로 사용됩니다.
- 예시로는 Java에서 String 클래스가 대표적인 불변 클래스입니다. String 객체를 한 번 생성하면 그 값을 변경할 수 없으며, 새로운 문자열을 생성할 때는 기존 문자열을 변경하는 것이 아니라 새로운 문자열을 생성합니다.
25. HashMap과 TreeMap의 차이를 설명하시오.
HashMap
과TreeMap
은 Java 컬렉션 프레임워크에서 맵(Map)을 구현한 클래스입니다.HashMap
- 해시 테이블을 기반으로 하며, 데이터를 해시 함수를 사용하여 저장합니다.
- 순서가 보장되지 않으며, 데이터 삽입, 삭제, 조회의 시간 복잡도가 O(1)에 가깝습니다.
- 키(Key)에 null을 허용하며, 중복된 키는 허용하지 않습니다.
TreeMap
- 이진 검색 트리를 기반으로 하며, 데이터를 정렬된 순서로 저장합니다.
- 데이터가 키 순서대로 정렬되며, 조회 작업의 시간 복잡도는 O(log n)입니다.
- 키에 null을 허용하지 않으며, 데이터가 키 순서대로 정렬됩니다.
26. ClassLoader에 대해 설명하시오.
ClassLoader
는 Java 가상 머신(JVM)에서 클래스 파일을 로드하고 해당 클래스를 실행 가능한 형태로 메모리에 적재하는 역할을 수행하는 시스템 컴포넌트입니다. ClassLoader는 다음과 같은 중요한 역할을 합니다- 클래스 파일을 찾아서 로드합니다.
- 클래스 파일을 바이트 코드로 읽어들여 메모리에 로딩합니다.
- 클래스 로딩 시 클래스 초기화를 수행합니다.
- 클래스 로딩에는 부모(ClassLoader 상속 구조)와 자식
ClassLoader
가 관여합니다.
- Java에서는 다양한
ClassLoader
가 제공되며, 각각의ClassLoader
는 클래스 로딩의 특정한 책임을 가지고 있습니다.
27. Garbage Collection에 대해 설명하시오.
Garbage Collection
은 프로그램에서 더 이상 사용되지 않는 객체(가비지)를 자동으로 인식하고 제거하는 메모리 관리 기법입니다. Java와 같은 고수준 언어에서는 개발자가 직접 메모리를 할당하고 해제하는 것이 아니라 가비지 컬렉터가 메모리를 관리합니다.- 가비지 컬렉션의 주요 원리는 더 이상 참조되지 않는 객체를 판단하는 것입니다. Java에서는 이를 “Reachability”라고 합니다.
- 자바의 가비지 컬렉터는 런타임 시간에 동작하며, 객체의 생성과 해제를 추적하여 메모리 누수를 방지합니다.
- 주요 가비지 컬렉션 알고리즘으로는
Mark and Sweep
,Generational Garbage Collection
등이 있으며, Java HotSpot VM은 성능 향상을 위해 여러 최적화 기법을 사용합니다.
28. 오픈 어드레싱과 세퍼레이트 체이닝 방식 설명.
- 오픈 어드레싱(Open Addressing)과 세퍼레이트 체이닝(Separate Chaining)은 해시 테이블의 충돌(두 개 이상의 항목이 같은 해시 버킷에 할당되는 경우)을 처리하는 방식입니다.
- 오픈 어드레싱
- 충돌이 발생하면 다른 해시 버킷에 데이터를 저장하는 방식입니다.
- 선형 탐사, 이차 탐사, 랜덤화 등의 방식으로 충돌을 해결할 수 있습니다.
- 일반적으로 저장 공간의 효율성이 떨어질 수 있지만, 캐시 효율성은 높을 수 있습니다.
- 세퍼레이트 체이닝
- 각 해시 버킷마다 연결 리스트 또는 다른 자료 구조를 사용하여 충돌된 데이터를 저장합니다.
- 충돌이 발생하더라도 버킷 내의 자료구조를 통해 데이터를 관리하기 때문에 저장 공간의 효율성이 높을 수 있습니다.
- 하지만 데이터가 많이 충돌할 경우 성능이 저하될 수 있습니다.
- 오픈 어드레싱
29. 모니터링 툴 뭐 써봤냐?
- 모니터링 도구는 시스템 및 애플리케이션의 성능과 상태를 추적하고 분석하는 데 사용됩니다. 몇 가지 대표적인 모니터링 도구는 다음과 같습니다:
- Prometheus: 오픈 소스 모니터링 및 알림 도구로, 메트릭 데이터 수집과 쿼리를 제공합니다.
- Grafana: 오픈 소스 대시보드 및 시각화 도구로, Prometheus와 함께 사용하여 시각적인 대시보드를 생성하고 메트릭 데이터를 시각화합니다.
- Nagios: 시스템 및 네트워크 모니터링에 사용되는 강력한 오픈 소스 도구로, 서비스 가용성 및 성능 모니터링을 수행합니다.
- ELK Stack (Elasticsearch, Logstash, Kibana): 로그 및 이벤트 데이터 수집, 저장 및 시각화를 위한 스택으로, Elasticsearch를 통해 데이터를 색인화하고 Kibana를 사용하여 시각화합니다.
- New Relic: 클라우드 기반 애플리케이션 성능 모니터링 도구로, 애플리케이션 트랜잭션, 인프라 구성 및 애플리케이션 성능을 모니터링합니다.
30. DFS와 BFS를 설명해주세요.
- DFS (Depth-First Search)
- 깊이 우선 탐색은 그래프나 트리에서 한 경로를 최대한 깊게 탐색한 후 다음 경로로 이동하는 방법입니다.
- 스택(Stack) 또는 재귀 함수를 사용하여 구현할 수 있으며, 재귀 호출을 통해 깊이 우선으로 탐색합니다.
- 주로 루트에서 목표 노드까지의 경로를 찾거나 연결된 모든 노드를 탐색할 때 사용됩니다.
- BFS (Breadth-First Search)
- 너비 우선 탐색은 그래프나 트리에서 한 레벨(깊이)씩 탐색하는 방법입니다.
- 큐(Queue)를 사용하여 구현하며, 현재 노드의 인접한 모든 노드를 먼저 방문한 후 다음 레벨로 이동합니다.
- 주로 최단 경로를 찾거나 모든 노드를 같은 레벨에서 탐색할 때 사용됩니다.
31. 힙덤프 해봤냐?
- 힙덤프(Heap Dump)는 Java 가상 머신의 힙 메모리에 있는 객체 정보를 파일로 덤프하는 작업을 의미합니다. 힙덤프는 메모리 누수 및 메모리 사용량 등의 디버깅 목적으로 사용됩니다.
- 힙덤프를 생성하려면 다음과 같은 방법을 사용합니다
- Java VisualVM, Eclipse MAT, jmap 등의 도구를 사용하여 수동으로 생성할 수 있습니다.
- OutOfMemoryError 예외가 발생한 경우 자동으로 힙덤프 파일을 생성하도록 설정할 수 있습니다.
- 힙덤프 파일은 메모리 덤프 분석 도구를 사용하여 객체의 상태, 참조 관계, 메모리 누수 등을 분석할 때 유용합니다.
32. 스레드 세이프 방법론 설명.
- 스레드 세이프(Thread-Safety)란 여러 스레드가 동시에 접근해도 안전하게 사용될 수 있는 코드를 의미합니다. 스레드 세이프한 코드를 작성하기 위해 다음과 같은 방법론을 사용할 수 있습니다:
- 락(Lock)을 사용하여 동기화: 여러 스레드가 공유 자원에 접근할 때 락을 획득하여 단 하나의 스레드만 접근할 수 있도록 합니다. synchronized 키워드나 ReentrantLock 클래스를 사용하여 동기화를 구현할 수 있습니다.
- 불변 객체(Immutable Object) 사용: 객체의 상태를 변경할 수 없도록 설계하여 스레드 간에 공유해도 안전하게 사용될 수 있도록 합니다.
- 스레드 로컬 저장(Thread-Local Storage): 스레드 간에 데이터를 공유하지 않고 각 스레드에게 독립적인 데이터를 제공하여 스레드 세이프성을 보장합니다.
- 원자적 연산(Atomic Operation) 사용: 원자적 연산은 여러 스레드에 의해 동시에 실행되더라도 결과가 일관되게 유지되는 연산을 말합니다. 자바에서 java.util.concurrent.atomic 패키지의 클래스들을 사용하여 원자적 연산을 수행할 수 있습니다.
33. 페이징 교체 알고리즘 중 LRU 설명해봐라.
LRU (Least Recently Used)
알고리즘은 페이지 교체 알고리즘 중 하나로, 메모리에서 가장 오랫동안 사용되지 않은 페이지를 교체하는 방식입니다.LRU 알고리즘
의 동작 방식- 페이지의 사용 기록을 유지하기 위해 스택, 큐 또는 연결 리스트 등의 자료 구조를 사용합니다.
- 페이지가 사용될 때마다 해당 페이지를 자료 구조의 맨 뒤로 이동시킵니다.
- 페이지 교체가 필요한 경우, 자료 구조의 맨 앞에 있는 페이지(가장 오랫동안 사용되지 않은 페이지)를 선택하여 교체합니다.
- LRU 알고리즘은 최적(Optimal) 알고리즘보다는 구현이 복잡하고 실용적으로 사용하기 어렵습니다. 이는 페이지 사용 이력을 정확하게 추적하기 위해서는 모든 메모리 액세스를 모니터링해야 하기 때문입니다. 대안적인 LRU 근사 알고리즘들이 있으며, 이러한 근사 알고리즘들은 실제 LRU와 비슷한 성능을 제공하는 동시에 구현이 더 쉽습니다. 예를 들어, 최근 사용된 페이지를 추적하기 위해 카운터를 사용하거나, 액세스된 페이지를 다른 자료 구조에 저장하고 재사용 여부를 판단할 때 이를 참고할 수 있습니다.
34. JUnit 어노테이션 동작 방식 설명.
JUnit
은 Java에서 단위 테스트를 작성하기 위한 프레임워크이며, 어노테이션을 사용하여 테스트 메소드를 정의하고 테스트를 실행합니다. 주요 JUnit 어노테이션과 동작 방식은 다음과 같습니다:@Test
: 테스트 메소드를 정의할 때 사용하는 어노테이션으로, 해당 메소드가 테스트 케이스임을 표시합니다.@Before
: 각 테스트 메소드가 실행되기 전에 한 번 호출되는 메소드를 정의하는 어노테이션입니다.@After
: 각 테스트 메소드가 실행된 후에 한 번 호출되는 메소드를 정의하는 어노테이션입니다.@BeforeClass
: 해당 테스트 클래스가 로드되고 테스트 메소드가 실행되기 전에 한 번 호출되는 정적 메소드를 정의하는 어노테이션입니다.@AfterClass
: 해당 테스트 클래스의 모든 테스트 메소드가 실행된 후에 한 번 호출되는 정적 메소드를 정의하는 어노테이션입니다.@Ignore
: 해당 테스트 메소드를 무시하고 실행하지 않도록 지정하는 어노테이션입니다.
35. Functional Interface 종류 말해봐라.
Functional Interface
는 하나의 추상 메소드를 가지고 있는 인터페이스를 말합니다. Java 8부터 람다 표현식과 함께 사용되며, 함수형 프로그래밍을 지원합니다. 몇 가지 주요한 Java 내장 함수형 인터페이스는 다음과 같습니다java.util.function.Consumer<T>
: 값을 입력받아 아무 결과도 반환하지 않는 함수를 나타냅니다.java.util.function.Supplier<T>
: 아무 값도 입력받지 않고 값을 반환하는 함수를 나타냅니다.java.util.function.Function<T, R>
: 하나의 값(T)을 입력받아 다른 값(R)을 반환하는 함수를 나타냅니다.java.util.function.Predicate<T>
: 하나의 값(T)을 입력받아 부울 값을 반환하는 함수를 나타냅니다.
36. 스프링 빈 스코프 종류 말해봐 (싱글턴, 프로토타입, 리퀘스트, 세션, 글로벌 세션).
- 스프링에서 빈(Bean)은 객체를 관리하고 생성하는데 사용되며, 다양한 스코프(scope)를 가질 수 있습니다:
싱글턴(Singleton)
: 기본 스코프로, 스프링 컨테이너 내에서 하나의 빈 인스턴스를 공유합니다. 컨테이너 내에서 동일한 빈을 여러 번 요청해도 항상 같은 인스턴스가 반환됩니다.프로토타입(Prototype)
: 각각의 빈 요청마다 새로운 인스턴스를 생성합니다. 요청할 때마다 새로운 객체가 생성되므로 다른 스코프보다 메모리 사용량이 높을 수 있습니다.리퀘스트(Request)
: 웹 애플리케이션에서 사용되며, 각 HTTP 요청마다 새로운 빈 인스턴스를 생성합니다. 주로 웹 애플리케이션의 요청 당 데이터를 저장하기 위해 사용됩니다.세션(Session)
: 웹 애플리케이션에서 사용되며, 각 HTTP 세션마다 새로운 빈 인스턴스를 생성합니다. 세션에 관련된 데이터를 저장하기 위해 사용됩니다.글로벌 세션(Global Session)
: 포털 애플리케이션에서 사용되며, 여러 세션 간에 공유되는 빈 인스턴스를 생성합니다.
37. RESTful API 메소드 중 PUT 대신 쓸 수 있는 것은?
- RESTful API에서 PUT 메소드는 리소스를 업데이트하는 데 사용됩니다. PUT 메소드는 주어진 리소스의 상태를 완전히 교체하는 역할을 합니다. 따라서 리소스를 부분적으로 업데이트하려면 PATCH 메소드를 사용할 수 있습니다.
- PATCH 메소드는 리소스의 일부만 업데이트하고 나머지 부분은 변경하지 않습니다. 이렇게 하면 클라이언트가 리소스의 특정 필드만 업데이트할 수 있으므로 효율적인 업데이트가 가능합니다.
38. HTTP/2.0 써봤음?
HTTP/2.0
는 HTTP/1.1의 후속 버전으로, 성능을 향상시키기 위한 여러 기술적 개선을 도입한 프로토콜입니다. 몇 가지 주요 특징과 개선점은 다음과 같습니다:- 다중화(Multiplexing): HTTP/2.0은 하나의 TCP 연결을 통해 여러 개의 요청과 응답을 동시에 처리할 수 있습니다. 이를 통해 브라우저와 서버 간의 라운드트립 횟수를 줄여 성능을 향상시킵니다.
- 헤더 압축(Header Compression): HTTP/1.1에서는 헤더 정보가 반복되어 전송되는데, HTTP/2.0은 헤더 필드를 인코딩하여 전송하므로 더 적은 대역폭을 사용합니다.
- 서버 푸시(Server Push): 서버가 클라이언트의 요청 없이 리소스를 프로액티브하게 전송할 수 있습니다. 예를 들어, 클라이언트가 HTML 파일을 요청할 때 서버는 필요한 CSS 및 JavaScript 파일을 함께 보낼 수 있습니다.
- 이진 프레임(Binary Frames): HTTP/2.0에서는 데이터를 이진 프레임으로 전송하므로 효율성이 향상되고, 텍스트 기반의 프로토콜인 HTTP/1.1보다 빠릅니다.
- 스트림(Streams): HTTP/2.0에서는 다양한 우선순위를 가진 스트림을 사용하여 요청과 응답을 병렬로 처리할 수 있습니다.
- HTTP/2.0는 웹 성능을 향상시키고 빠르게 로딩되는 웹 페이지를 제공하기 위한 표준으로 채택되어 있으며, 대부분의 현대적인 웹 브라우저와 웹 서버에서 지원됩니다. 이를 통해 웹 애플리케이션의 성능과 사용자 경험을 향상시킬 수 있습니다.
39. GC 종류 말해보고, 설명해봐.
가비지 컬렉션(Garbage Collection)
은 더 이상 사용되지 않는 객체를 자동으로 제거하는 메모리 관리 기법입니다. 다양한 가비지 컬렉션 알고리즘이 존재하며, 주요한 종류와 간단한 설명은 다음과 같습니다Serial GC
: 싱글 스레드로 동작하며, 쉽고 간단한 알고리즘입니다. 주로 작은 규모의 애플리케이션에서 사용됩니다.Parallel GC
: 다중 스레드로 동작하며, 메모리 부족 시간을 줄이기 위한 알고리즘입니다. 주로 백그라운드에서 가비지 컬렉션을 실행하여 애플리케이션의 성능을 향상시킵니다.CMS (Concurrent Mark-Sweep) GC
: 메모리 부족 시간을 최소화하고 일시 중단 시간을 최소화하는 데 중점을 둔 알고리즘입니다. 주로 대규모 서버 애플리케이션에서 사용됩니다.G1 (Garbage-First) GC
: CMS GC의 개선된 버전으로, 일시 중단 시간을 더 줄이고 메모리를 효율적으로 관리하는 알고리즘입니다. 대규모 힙을 가진 애플리케이션에 적합합니다.ZGC
: Oracle에서 개발한 가비지 컬렉션 알고리즘으로, 높은 처리량과 낮은 일시 중단 시간을 제공합니다. 대규모 메모리와 대규모 프로세스에 적합합니다.Shenandoah GC
: 빠른 일시 중단 시간을 제공하는 가비지 컬렉션 알고리즘으로, 대규모 메모리를 사용하는 애플리케이션에 적합합니다.
40. n:1 그냥 쓰면 쿼리 엄청 많이 써지는데 해결 전략 말해보세요.
- N+1 쿼리 문제는 ORM(Object-Relational Mapping)을 사용하는 애플리케이션에서 발생하는 일반적인 성능 문제입니다. 이 문제를 해결하기 위한 전략은 다음과 같습니다
- Eager Loading: 관련된 데이터를 사전에 로드하여 N+1 문제를 방지합니다. Hibernate에서는 @ManyToOne(fetch = FetchType.LAZY)와 같이 지연 로딩을 사용하여 관련 엔티티를 필요한 시점에 로드할 수 있습니다.
- Fetch Join: JPA에서는 JPQL(JPA Query Language)에서 JOIN FETCH를 사용하여 관련 엔티티를 함께 로드할 수 있습니다.
- Batch Fetching: 관련 엔티티를 일괄적으로 로드하는 방법을 사용하여 N+1 문제를 해결합니다. Hibernate에서는 @BatchSize 애노테이션을 사용하여 일괄적으로 로드할 엔티티의 크기를 설정할 수 있습니다.
- DTO 사용: 필요한 데이터만 포함한 DTO(Data Transfer Object)를 사용하여 쿼리 결과를 가져옵니다. 이로써 필요한 데이터만 로드되므로 N+1 문제가 해결됩니다.
41. DB 구조 설명
데이터베이스(DB)
구조는 데이터를 저장하고 관리하는 방식을 정의한 것입니다. 일반적으로 다음과 같은 주요 구성 요소로 구성됩니다테이블(Table)
: 데이터가 저장되는 기본 단위로, 행과 열로 구성됩니다. 각 테이블은 특정한 유형의 데이터를 저장합니다.열(Column)
: 테이블 내에서 데이터의 속성 또는 필드를 나타냅니다. 각 열은 데이터 유형과 제약 조건을 가질 수 있습니다.행(Row)
: 테이블 내에서 개별 데이터 레코드를 나타냅니다. 각 행은 테이블의 열에 대한 값들을 가집니다.기본 키(Primary Key)
: 테이블에서 각 행을 고유하게 식별하는 데 사용되는 열 또는 열의 조합입니다.외래 키(Foreign Key)
: 다른 테이블과의 관계를 나타내며, 한 테이블의 기본 키를 다른 테이블의 열로 참조합니다.인덱스(Index)
: 검색 속도를 향상시키기 위한 데이터베이스 객체로, 특정 열 또는 열의 조합에 대한 빠른 검색을 가능하게 합니다.뷰(View)
: 하나 이상의 기본 테이블에서 파생된 가상 테이블로, 특정 조건에 따라 데이터의 일부 또는 변형된 데이터를 조회할 때 사용됩니다.
42. IOC와 순수 개발자가 생성한 코드가 무슨 차이?
IOC (Inversion of Control)
는 프로그래밍 패러다임으로, 제어의 역전을 의미합니다. 스프링 프레임워크와 같은 IOC 컨테이너를 사용하면 애플리케이션의 객체 생성과 관리를 프레임워크가 담당하고, 개발자는 객체 간의 의존성을 설정합니다. 이에 반해 순수 개발자가 직접 코드를 작성하는 경우에는 개발자가 객체의 생성과 의존성 관리를 직접 처리합니다.- IOC와 순수 개발자가 생성한 코드의 차이
IOC
는 객체의 라이프사이클 관리와 의존성 주입을 자동으로 처리하므로 개발자는 객체 생성 및 초기화에 대한 부분에 신경을 덜 쓸 수 있습니다. 이로 인해 코드의 유지보수와 테스트 용이성이 향상됩니다.IOC
``` 컨테이너를 사용하면 객체 간의 결합도가 낮아지므로 느슨한 결합(Loose Coupling)이 가능해집니다. 이는 코드의 재사용성과 확장성을 향상시킵니다.- 순수 개발자가 생성한 코드는 객체의 생성 및 초기화, 의존성 주입 등을 수동으로 처리해야 하므로 보다 복잡하고 실수하기 쉽습니다.
IOC
는 코드의 구조를 제어하기 쉽게 만들어주며, 개발자가 비즈니스 로직에 집중할 수 있도록 합니다.
43. 개발자가 객체 관리를 어떻게 하는지?
- 개발자가 객체 관리를 수동으로 처리하는 경우, 일반적으로 다음과 같은 작업을 수행합니다
- 객체 생성: new 키워드를 사용하여 객체를 직접 생성합니다.
- 객체 초기화: 생성된 객체의 필드를 초기화하고 설정합니다.
- 의존성 주입: 다른 객체에 대한 의존성을 수동으로 주입합니다.
- 객체 수명 주기 관리: 객체의 수명 주기를 관리하고 필요한 경우 수동으로 객체를 소멸시킵니다.
- 객체 범위 관리: 객체의 범위(scope)를 관리하고 필요한 경우 객체를 싱글턴으로 유지하거나 새로 생성합니다.
- 이러한 작업은 객체 관리의 복잡성을 증가시킬 수 있으며, 실수와 버그를 발생시킬 가능성이 높습니다. 따라서 대부분의 프레임워크와 컨테이너(예: 스프링 컨테이너)를 사용하여 객체 관리를 자동화하고 개발자가 객체 생성 및 관리에 대해 걱정할 필요가 없도록 합니다. IOC 컨테이너는 객체의 라이프사이클을 관리하고 의존성 주입을 제공하므로 개발자는 비즈니스 로직에 집중할 수 있습니다.
44. 인젝션 주입 방법과 각 차이점
의존성 주입(Dependency Injection)
은 객체 간의 의존성을 관리하고 주입하는 방법입니다. 다음은 주요한 인젝션 주입 방법과 그 차이점입니다- 생성자 주입(Constructor Injection): 의존성을 주입받는 클래스의 생성자를 통해 의존성을 주입하는 방법입니다. 이 방법은 의존성을 필수로 주입받아야 할 때 주로 사용됩니다. 코드의 안정성과 불변성을 유지하는 데 도움이 됩니다.
- 필드 주입(Field Injection): 의존성을 주입받는 클래스의 필드에 주입하는 방법입니다. 주로 스프링 프레임워크와 같은 IOC 컨테이너에서 사용되며, 주입받는 필드를 @Autowired 또는 @Inject와 같은 어노테이션으로 표시합니다. 필드 주입은 간편하지만 테스트와 같은 상황에서 어려움을 겪을 수 있습니다.
- 세터 주입(Setter Injection): 의존성을 주입받는 클래스의 세터 메소드를 통해 의존성을 주입하는 방법입니다. 세터 주입은 선택적으로 의존성을 주입받을 수 있으며, 객체 생성 후에 의존성을 변경할 수 있습니다. 이는 특정 의존성이 필수가 아닌 경우에 유용합니다.
- 생성자 주입은 의존성 주입의 가장 권장되는 방법으로 간주되며, 코드 안정성과 테스트 용이성을 제공하는 반면, 필드 주입과 세터 주입은 특정 상황에 유용할 수 있지만, 주입되는 의존성이 변경되기 쉬운 문제가 있을 수 있습니다.
45. INDEX 원리
INDEX
는 데이터베이스의 성능을 향상시키기 위한 데이터 구조입니다. INDEX는 테이블 내의 특정 열(칼럼)에 대한 빠른 검색을 가능하게 합니다. 다음은 INDEX의 동작 원리입니다- INDEX는 B-트리(B-tree) 또는 해시(Hash)와 같은 데이터 구조를 사용하여 구현됩니다. 가장 일반적인 INDEX 형태는 B-트리입니다.
- INDEX를 생성할 때, 데이터베이스는 테이블의 각 행에 대한 키(Key)를 추출하여 INDEX 트리에 저장합니다. 이 키는 검색에 사용됩니다.
- 검색할 때, 데이터베이스 엔진은 INDEX를 사용하여 검색 키를 빠르게 찾아갑니다. 이를 통해 테이블의 모든 행을 스캔하지 않고도 원하는 결과를 검색할 수 있습니다.
- INDEX는 정렬된 구조로 유지되므로 범위 검색(range scan)도 효율적으로 수행할 수 있습니다.
- 하지만 INDEX는 삽입, 수정, 삭제 작업이 발생할 때마다 업데이트되어야 하므로 적절한 INDEX를 선택하고 관리하는 것이 중요합니다.
- 적절한 INDEX를 선택하지 않으면 오히려 성능 저하를 일으킬 수 있으므로, 테이블의 쿼리 패턴과 데이터베이스 엔진의 종류에 따라 INDEX를 설계해야 합니다.
46. INDEX 어떤 컬럼을 사용해야 좋은지 PK를 제외
- INDEX를 어떤 컬럼에 생성해야 하는지 결정하는 것은 데이터베이스 쿼리 패턴과 성능 요구사항에 따라 다릅니다. 주로 다음과 같은 컬럼에 INDEX를 생성합니다
- 검색 조건이 자주 사용되는 컬럼: 특정 컬럼을 자주 검색하는 쿼리가 있는 경우 해당 컬럼에 INDEX를 생성하면
검색 성능이 향상됩니다.
- 조인 조건에 사용되는 컬럼: 여러 테이블을 조인하는 경우, 조인 조건에 사용되는 컬럼에 INDEX를 생성하면
조인 작업의 성능이 향상됩니다.
- 정렬 및 그룹화에 사용되는 컬럼: ORDER BY 또는 GROUP BY 절에 사용되는 컬럼에 INDEX를 생성하면
정렬 및 그룹화 작업이 빨라집니다.
- 검색 조건이 자주 사용되는 컬럼: 특정 컬럼을 자주 검색하는 쿼리가 있는 경우 해당 컬럼에 INDEX를 생성하면
- 주의할 점은 모든 컬럼에 INDEX를 생성하는 것이 좋지 않으며, INDEX를 과도하게 생성하면 INSERT, UPDATE, DELETE 작업의 성능에 부정적인 영향을 미칠 수 있습니다. 따라서 INDEX를 선택적으로 사용해야 합니다.
47. INDEX 내부 구조
- INDEX는
B-트리(B-tree)
또는해시(Hash)
와 같은 데이터 구조로 구현됩니다. INDEX의 내부 구조는 주로 B-트리로 구현되며, 다음은 B-트리 INDEX의 간단한 내부 구조에 대한 설명입니다- B-트리는 균형 이진 트리(Binary Tree)의 일종으로, 각 노드는 여러 개의 키와 자식 노드에 대한 참조를 가집니다.
- B-트리는 균형을 유지하며 모든 리프 노드가 동일한 레벨에 있는 트리입니다. 이는 검색 속도를 일정하게 유지합니다.
- INDEX에는 테이블의 각 행에 대한 키(Key)가 저장되며, 이 키는 정렬된 순서로 관리됩니다.
- B-트리의 각 노드에는 일정 개수의 키와 각 키에 대한 자식 노드에 대한 참조가 저장됩니다. 노드의 크기는 데이터베이스 시스템에 따라 다를 수 있습니다.
- 검색 작업 시, 루트 노드에서 시작하여 키를 비교하고 적절한 자식 노드로 이동하여 키를 찾아갑니다. 이를 반복하여 검색 작업을 수행합니다.
- B-트리의 장점은 검색, 범위 검색, 정렬, 그룹화와 같은 작업을 효율적으로 수행할 수 있으며, 레코드 삽입, 수정, 삭제 작업도 비교적 효율적으로 처리할 수 있습니다.
- B-트리는 데이터베이스 시스템에서 자동으로 관리되며, 개발자가 직접 B-트리를 조작할 필요가 없습니다.
48. HTTP의 원리
HTTP(Hypertext Transfer Protocol)
는 웹에서 데이터를 주고받기 위한 프로토콜입니다. HTTP의 작동 원리는 다음과 같습니다:- 클라이언트 요청: 웹 브라우저 또는 다른 클라이언트 애플리케이션은 서버에 HTTP 요청을 보냅니다. 요청은 URL(Uniform Resource Locator)을 통해 서버와 요청할 리소스(웹 페이지, 이미지 등)를 지정합니다.
- 서버 응답: 서버는 클라이언트 요청을 받아 해당 요청에 대한 응답을 생성합니다. 응답은 HTTP 상태 코드(200 OK, 404 Not Found 등)와 함께 요청한 리소스의 데이터를 포함할 수 있습니다.
- TCP/IP 연결: HTTP는 기본적으로 TCP/IP 프로토콜을 기반으로 작동합니다. 클라이언트와 서버 간에 TCP/IP 연결이 설정되어 데이터가 안정적으로 전송됩니다.
- 요청 메소드: HTTP 요청은 메소드(예: GET, POST, PUT, DELETE)를 사용하여 요청의 종류를 지정합니다. 예를 들어, GET 메소드는 리소스를 가져오기 위해 사용되고, POST 메소드는 데이터를 서버로 제출하기 위해 사용됩니다.
- 요청 헤더: 클라이언트는 요청 헤더에 추가 정보(예: 사용자 에이전트, 쿠키, 인증 정보)를 포함할 수 있습니다.
- 응답 헤더: 서버는 응답 헤더에 추가 정보(예: 캐시 제어, 콘텐츠 타입)를 포함할 수 있습니다.
- 콘텐츠 전송: 클라이언트와 서버 간에 데이터가 전송되며, 이 데이터는 요청된 리소스의 내용을 포함합니다.
- 연결 종료: 데이터가 전송된 후에는 TCP/IP 연결이 종료됩니다. 이때, 연결을 닫거나 재사용할 수 있습니다.
- 상태 코드: 클라이언트는 서버에서 받은 상태 코드를 분석하여 요청이 성공적으로 처리되었는지 또는 오류가 발생했는지 확인합니다.
- 웹 브라우저 렌더링: 클라이언트(웹 브라우저)는 받은 응답 데이터를 렌더링하여 사용자에게 웹 페이지를 표시합니다.
49. HTTP 1.1, 2.0, 3의 차이에 대해서 설명
HTTP 1.1
- HTTP 1.1은 오랜 기간 동안 사용된 HTTP 버전으로, 기본적인 웹 통신 프로토콜입니다.
- 주요 특징
- 지속적인 연결(Persistent Connection): 하나의 TCP 연결을 통해 여러 요청 및 응답을 처리할 수 있어 연결 설정 및 해제의 오버헤드를 감소시킵니다.
- 파이프라인(Pipelining): 여러 요청을 동시에 보내고, 서버로부터 동시에 응답을 받아 처리할 수 있도록 합니다. 하지만 이 기능이 제대로 구현되지 않은 경우 렌더링 블로킹 문제가 발생할 수 있습니다.
- 단점
- 헤더 필드의 중복 전송: 요청과 응답의 각각의 메시지에서 헤더 필드가 중복으로 전송되어 대역폭 낭비가 발생합니다.
- 느린 페이지 로딩: 병렬 요청 처리에 제약이 있어 웹 페이지의 로딩이 느릴 수 있습니다.
HTTP 2.0
- HTTP 2.0은 HTTP 1.1을 대체하는 새로운 버전으로, 성능을 향상시키기 위한 여러 기술적 개선을 도입했습니다.
- 주요 특징
- 다중화(Multiplexing): 하나의 TCP 연결을 통해 여러 요청과 응답을 동시에 전송하고 병렬 처리합니다. 이로써 렌더링 블로킹 문제가 해결됩니다.
- 헤더 압축: 헤더 필드를 압축하여 대역폭을 절약합니다.
- 서버 푸시(Server Push): 서버가 클라이언트의 요청 없이 리소스를 미리 보내는 기능으로, 페이지 로딩 속도를 향상시킵니다.
- 이진 프레임 형식: HTTP 2.0은 이진 형식으로 데이터를 전송하므로 효율적인 데이터 전송이 가능합니다.
- 단점
- 복잡성: HTTP 2.0은 구현이 복잡하고, 일부 네트워크 장비에서 지원이 제한적일 수 있습니다.
HTTP 3.0
- HTTP 3.0은 HTTP 2.0을 더욱 개선하기 위한 노력의 일환으로, QUIC(Quick UDP Internet Connections) 프로토콜을 기반으로 동작합니다.
- 주요 특징
- QUIC 프로토콜 사용: QUIC는 UDP(사용자 데이터그램 프로토콜)를 사용하여 전송되므로 연결 설정 및 데이터 전송이 빠릅니다.
- 레이턴시 감소: 연결 설정 및 레이턴시를 감소시켜 웹 페이지 로딩 속도를 향상시킵니다.
- 신뢰성 향상: 패킷 손실에 대한 신속한 복구 및 보안 향상을 제공합니다.
- 단점
- 아직까지 HTTP 3.0을 지원하는 서버와 클라이언트가 제한적이며, 네트워크 환경에 따라 성능 차이가 발생할 수 있습니다.
- HTTP 1.1, 2.0, 3.0은 웹의 성능 및 보안을 향상시키기 위한 지속적인 노력의 결과물로, 선택할 버전은 웹 애플리케이션의 요구 사항과 지원하는 환경에 따라 다를 수 있습니다.