자바 컴파일러가 자바 소스파일을 컴파일한다. 이때 나오는 파일은 자바 바이트 코드(.class)파일로 아직 컴퓨터(=JVM자바 가상 머신)가 읽을 수 없는 코드이다. (바이트 코드의 각 명령어는 1바이트 크기의 Opcode와 추가 피연산자로 이뤄져있다.)
컴파일된 바이트 코드(.class)를 JVM의 클래스 로더(Class Loader)에게 전달된다.
클래스 로더 세부 동장
로드 : 클래스 파일을 가져와서 JVM의 메모리에 로드한다.
검증 : 자바 언어 명세 및 JVM 명세에 명시된 대로 구성되어 잇는지 검사
준비 : 클래스가 필요로 하는 메모리를 할당
분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경
초기화 : 클래스 변수들을 적절한 값으로 초기화
클래스 로더는 동적로딩(Dynamic Loding)을 통해 필요한 클래스들을 로딩 및 링크하여 런타임 데이터 영역(Runtime Data area), 즉 JVM의 메모리에 올립니다.
실행엔진(Exectution Engine)은 JVM메모리에 올라온 바이트 코드를 명령어 단위로 하나씩 가져와서 실행한다.
인터프리터 방식 : 바이트 코드 명령어를 하나씩 읽어서 해석하고 실행한다. 하나하나의 실행은 빠르나, 전체적인 실행 속도가 느리다.
JIT 컴파일러(Just-In-Time Compiler) 방식 : 인터프리터 단점을 보완하기 위해 도입된 방식으로 바이트 코드 전체를 컴파일하여 바이너리 코드로 변경하고 이후에는 해당 메서드를 더 이상 인터프리팅 하지 않고, 바이너리 코드로 직접 실행하는 방식
요약
순서
Input
Exe(실행)
Output
1
개발자가 작성한 (.java)
자바 컴파일러가 컴파일
바이트 코드(.class)
2
바이트 코드(.class)
JVM 클래스 로더의 동적로딩
런타임 데이터 영역(=JVM 메모리)에 올린다.
3
JVM 메모리에 올라온 바이트 코드 (.class)
- JVM내에서 인터프리터 or JIT 컴파일러 방식
런타임 시스템 -> 운영체제 ->하드웨어
[자바 컴파일러] 1. helloworld.java 작성 2. javac명령어(java compiler)를 통해 helloworld.java 파일을 helloworld.class파일로 변환 (컴파일러가 수행) [자바 인터프리터] 3. 컴파일러에 의해 변환된 helloworld.class 내의 바이트 코드를 특정 환경의 기계(다른 OS)에서 실행될 수 있도록 변환한다. -> 예로 IBM PC에서 작성된 프로그램을 매킨토시에서도 실행할 수 있도록 변환하는 의미이다. 인터프리터가 하는 일자바는 기본적으로 컴파일과 인터프리트를 병행하는 것일까? - 인터프리팅은 플랫폼(OS)에 종속되지 않는다. 물론 컴파일러를 먼저 수행하고 인터프리팅을 하는 과정 때문에 컴파일 과정만 하는 필요한 프로그래밍 언어보다는 속도가 느리다. - 자바 바이트 코드는 컴퓨터와 프로그램 사이에 별도의 버퍼역할을 한다. 자바 인터프리터로 인행 바이러스나 악성 프로그램을 대응 하는 가드 같은 보안 계층에 의해 보호 될 수 있다. 이유는 자바와 자바 바이트 코드의 좋바으로 플랫폼에 독립적이고 안전한 환경을 제공하기 때문이다.
결론 컴파일이라는 과정은 결국 인간이 쓴 인간어(java)를 기계어(Machine Language)로 바꾸는 과정이라고 생각합니다. 자바의 컴파일의 특징은 Java Compiler을 거쳐 만들어진 바이트 코드인 (.class)파일을 interpreter를 통해 기계어로 변환하는 과정에서 interpreter를 사용하므로서 OS에 종속되지 않습니다. (보안에도 좋다)
컴파일러 vs 인터프리터
컴파일러(번역기)
인터프리터(실행기)
방식
- 고급 언어로 작성된 프로그램을 목적 프로그램으로 번역 후 링킹 작업을 통해 실행 프로그램을 생성한다. - 자바는 javac로 컴파일하고 java 실행 시 중간언어(클래스 파일)을 한줄씩 자바 인터프리터가 번역하기에 컴파일 언어 이면서 인터프리터 언어이다.
- 컴파일러는 전체 소스코드를 보고 명령어를 수집하고 재구성한다. 즉 인터프리터 처럼 중간 형태로 변환 시킨 후 실행하지 않고 고레벨 언어를 바로 기계어로 변환한다.
- 고급 언어로 작성된 프로그램을 한줄한줄씩 번역에서 OS에서 인식하는 기계어로 번역하는 역할
- 바이트 코드(.class)를 인터프리터가 한 줄 씩 해석하면서 기계어로 번역한다.
개발 편의성
코드를 수정하고 실행하려면 컴파일러 다시 실행
코드를 수정하고 즉시 실행 가능
실행 속도
빠르다,
느리다.
보안
코드가 유출되지 않는다.
유출될 수 있다.
파일 용량
프로그램의 실행 파일 전체를 전송해야 하므로, 용량이 크다.
프로그램의 코드만 전송하면 실행이 되므로, 용량이 작다.
프로그래밍 언어
C, C++처럼 비교적 저수준에 가까운 언어
Python, Ruby처럼 비교적 고수준에 가까운 언어
흐름도
String, StringBuffer, StringBuilder의 차이 및 장단점
연산이 많지 않을때는 위의 나열된 어떤 클래스를 사용하더라도 이슈가 발생할 가능성이 거의 없다. 하지만 연산횟수가 많아지거나, 멀티쓰레드, Race condition 등의 상황이 자주 발생한다면 각 클래스이 특징을 이해하고 상황에 맞는 적절한 클래스를 사용해야한다.
- str이 가르키는 곳에 저장된 "hello"에 "world" 문자열을 더해 "hello world"로 변경한 것으로 착각할 수 있다.
- 하지만 기존 "hello" 값이 들어가있던 String 클래스의 참조변수 str이 "hello world"라는 값을 가지고 있는 새로운 메모리영역을 가리키게 변경었다.
- 처음 선언했던 "hello"로 값이 할당되어 있던 메모리 영역은 Garage로 남아있다가 GC(gabage colltion)에 의해 사라지게된다.
- String 클래스는 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성된 것이다.
즉 hello + wolrd가 된게 아니라 hello 삭제 -> hello wolrd 생성 개념이다. 이유는 불면 속성 때문이다.
단점은 문자열 추가, 수정, 삭제가 빈번하게 발생하는 알고리즘에 String 클래스를 사용하면 힙 메모리(Heap)에 많은 가비지가 생성되어 힙메모리가 부족할 수 있다.
불변 객체(immutable) 불변 객체는 완전히 생성된 후에도 내부 상태가 일정하게 유지 되는 개체입니다. 즉 객체가 변수에 할당되면 참조를 업데이트 하거나 내부 상태를 어떤 방법으로도 변경할 수 없습니다.
왜 String이 불변 객체 일까?(성능, 동기화, 캐싱, 보안) 1. 성능 - 자바에서 문자열은 정말 많이 사용된다. 그렇게 때문에 자바에서는 상수 풀이라는 것을 만들었다. 상수 풀이 무엇인가?
public class Test {
public static void main(String[] args) {
String s1 = "Hello World";
String s2 = "Hello World";
System.out.println(s1 == s2); // true
}
}
위의 코드 실행 과정을 분석해보면 문자열 s1에 해당하는 것을 상수 풀에서 검색을 한다. 없다면 상수 풀에 등록하고 해당하는 레퍼런스 값을 반환한다. s2 문자열도 마찬가지로 상수 풀에서 해당 문자열이 있는지 검색한다. s1을 이미 상수 풀에 등록했기 때문에 같은 레퍼런스로 반환한다.문자열 리터럴을 캐싱하고 재사용하면 문자열 풀의 다른 문자열 변수가 동일한 개체를 참고하기 때문에 힙 공간을 절약할 수 있다. 하지만 조회, 삭제, 수정이 자주 일어나는 환경에선 매우 좋지 못하다.
만약 String mutable(변화가능)하다면 String pool로 생성하여 공유가 불가능하다.
StringBuffer/StringBuilder 가변(mutable)
StringBuffer sb = new StringBuffer("hello");
sb.append(" world");
StringBuffer/StringBuilder
문자열의 추가, 수정, 삭제가 빈번하게 발생 할 때 사용하면 좋다. 따라서 .apped(), .delete() 등의 함수를 통해 동일 객체내에서 문자열을 변경하는 것이 가능하다.
JVM의 구조 1) Garbage Collecotor 2) Execution Engine 3) Class Loader 4) Runtime Data Area
(1) Class Loader
JVM 내로 클래스 파일을 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈입니다. 런타임 시에 동적으로 클래스를 로드합니다.
(2) Execution Engine
- 클래스 로더를 통해 JVM 내의 Runtime Data Area에 배치된 바이트 코트들을 명령어 단위로 읽어서 실행한다.
- 최초 JVM이 나왔을 당시에는 인터프리터 방식이었기 때문에 속도가 느리다는 단점이 있었지만 JIT 컴파일러 방식을 통해 이 점을 보완하였습니다.
- JIT는 바이트 코드를 어셈블러 같은 네이티브 코드로 바꿈으로써 실행이 빠르지만 역시 변환하는 비용이 발생한다.
- 같은 이유로 JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다가 일정한 기준이 넘어가면 JIT 컴파일러 방식으로 실행한다.
(3) Garbage Collector
Garbage Collector(GC)는 힙 메모리 영역에 생성된 객체들 중에서 참조되지 않은 객체들을 탐색 후 제거하는 역할을 한다. 이때, GC가 역할을 하는 시간은 언제인지 정확히 알 수 없다.
(4) Runtime Data Area
JVM 메모리 영역으로 자바 애플리케이션을 실행 할 때 사용되는 데이터들을 적재하는 영역입니다. 이 영역은 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack 으로 나눌 수 있다.
Runtime Data Area 영역
설명
(1) Method Area : 모든 쓰레드가 공유하는 메모리 영역이다. 메소드 영역은 클래스, 인터페이스, 메소드, 필드, static 변수 등의 바이트 코드를 보관한다. (2) Heap Area : 모든 쓰레드가 공유하며, new 키워드로 생성된 객체와 배열이 생성되는 영역이다. 또한, 메소드 영역에 로드된 클래스만 생성이 가능하고 GC가 참조되지 않은 메모리를 확인하고 제거하는 영역이다. (3) Stack area : 메소드 호출 시마다 각각의 스택 프레임(그 메서드만을 위한 공간)이 생성 그 메서드 안에서 사용되는 값을 저장하고, 호출된 연신 시 임시로 저장하며 메서드 수행이 끝나면 프레임별로 삭제(후입선출) (4)PC Register : 쓰레드가 시작될 때 생성되며, 생성될 때마다 생성되는 공간으로 쓰레드마다 하나씩 존재합니다. 쓰레드가 어떤 부분을 무슨 명령으로 실행해야할 지에 대한 기록을 하는 부분으로 현재 수행중인 JVM 명령의 주소를 갖는다. (5) Native method stack 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역이다.
인터페이스(Interface)와 추상 클래스(abstract class)
추상 클래스(abstract class)
클래스를 설계도라 하면, 추상 클래스는 미완성 설계도에 비유할 수 있다.
추상 메서드
선언부만 작성하고 구현부는 작성하지 않은 채 남겨 둔 것이며 추상 메서드는 상속받는 클래스에 따라 달라질 수 있다.
- 이를 상속할 각 객체들의 공통점을 찾아 추상화시켜 놓은 것으로, - 상속 관계를 타고 올라갔을 때 같은 부모 클래스를 상속하며 부모 클래스가 가진 기능들을 구현해야할 경우 사용한다.
- 상속 관계를 올라갔을 때 다른 조상 클래스를 상속하더라도, 같은 기능이 필요할 경우 사용한다.
적절한 케이스
- 관련성이 높은 클래스 간에 코드를 공유하고 싶은 경우 - 추상 클래스를 상속 받을 클래스들이 공통으로 가지는 메소드와 필드가 많거나 public이외의 접근자(protected, private) 선언이 필요한 경우 - non-static, non-final 필드 선언이 필요한 경우
- 서로 관련성이 없는 클래스들이 인터페이스를 구현하게 되는 경우 - 특정 데이터 타입의 행동을 명시하고 싶은데, 그 행동이 구현되는지 신경쓰지 않는 경우 - 다중상속을 허용하고 싶은 경우
차이점!!!
1. 사용의도 차이점 - 추상클래스는 IS -A "~이다". 인터페이스는 HAS -S "~을 할 수 있는" 자바의 특성상 한개의 클래스만 상속이 가능하여 해당 클라스의 구분을 추상 클래스 상속을 통해 해결하고, 할 수 있는 기능들을인터페이스로 구현합니다.
2. 공통된 기능 사용 여부 만약 모든 클래스가 인터페이스를 기본 틀을 구성한다면, 공통으로 필요한 기능들도 모든 클래스에서 오버라이딩 하여 재정의 해야하는 번거로움이 있습니다. 공통된 기능이 필요하다면 추상클래스를 이용해서 일반 메서드를 작성하여 자식 클래스에서 사용할 수 있도록 하면된다. 만약 각각 다른 추상클래스를 상속하는데 공통된 기능이 필요하하다면, 해당 기능을 인터페이스로 작성해서 구현한다. ex) 추상클래스 : 홍길동은 생명체를 상속받는다. 참새는 생명체를 상속받는다. 생명체는 숨쉬기는 기능이있다. (공통) 인터페이스 : 홍길동은 talkable 인터페이스를 다중 상속한다. 참새는 flyable을 상속받는다. 각각 공통된 기능이 아니므로 interface를 implements한다.
Call by Value와 Call by reference in Java
말 그대로 '값에 의한 호출' 이냐, '참조에 의한 호출' 이냐 라고 할 수 있다.
- Call by value는 메서드 호출 시에 사용되는 인자의 메모리에 저장되어 있는 값(value)을 복사하여 보낸다. 주소 값을 보낸 게 아니어서 메서드 밖에선 값이 안 변한다. - Call by reference는 메서드 호출 시에 사용되는 인자가, 값이 아닌 주소(Address)를 넘겨줌으로써, 주소를 참조(Referece) 하여 데이터를 변경할 수 있습니다.
//callByValue
Class CallByValue{
public static void swap(int x, int y) {
int temp = x;
x = y;
y = temp;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("swap() 호출 전 : a = " + a + ", b = " + b);
swap(a, b);
System.out.println("swap() 호출 후 : a = " + a + ", b = " + b);
}
}
결과 :
호출 전 : a=10 b= 20
호출 후 : a=10 b= 20
//=================================================================================
//callByReference
Class CallByReference{
int value;
CallByReference(int value) {
this.value = value;
}
public static void swap(CallByReference x, CallByReference y) {
int temp = x.value;
x.value = y.value;
y.value = temp;
}
public static void main(String[] args) {
CallByReference a = new CallByReference(10);
CallByReference b = new CallByReference(20);
System.out.println("swap() 호출 전 : a = " + a.value + ", b = " + b.value);
swap(a, b);
System.out.println("swap() 호출 전 : a = " + a.value + ", b = " + b.value);
}
}
결과 :
호출 전 : a=10 b= 20
호출 후 : a=20 b= 10
그렇다면 Java는 call by value 일까? call by reference 일까?
사실 자바는 Call by value이냐, Call by reference이냐 로 의견이 분분합니다. 메모리에 저장 된 주소를 보내는 것도 물리적 관점에서 보면 값으로 볼 수 있기 때문인데요, 이 문제에 대해서도 한번 생각해 보신다면 좋을 것 같습니다. 결론은 메모리에 저장된 주소(값)을 보내는 것이므로 자바는 Call by value 이다. 참고 : http://wonwoo.ml/index.php/post/1679
결론, Java는 항상 call by value이다.
- 자바는 객체의 주소를 가져오는 방법이 없다. 만약 call by reference를 지원한다면 주소를 가져오는 방법을 지원해야 한다. 맞네..C처럼 레퍼런스를 써서 가져오든, 포인터를 써서 가져오던지 해야하는데 그게 없다.
👀 String Pool이란? Java Heap Memory 내에 문자열 리터럴을 저장한 공간.(HashMap으로 구현) 한번 생성된 문자열 리터럴은 변경될 수 없다.문자열 리터럴은 클래스가 메모리에 로드될 때 자동적으로 미리 생성된다.
리터럴로 문자열을 생성하면(내부적으로 String.intern() 호출) String Pool에 같은 값이 있는지 찾는다.같은 값이 있으면 그 참조값이 반환된다.같은 값이 없으면 String Pool에 문자열이 등록된 후 해당 참조값이 반환된다.
String 객체 생성
설명
위의 두가지 방식은 String 객체를 생성한다는 사실은 같지만, JVM이 관리하는 메모리 구조상에서 명백히 다르다. 아래의 그림은 두가지 방법으로 String 객체를 생성했을 때, JVM 메모리상에 어떻게 존재하는지에 대한 이해를 돕는 그림이다.
Java Garbage Collector 의동작원리
JVM에서 GC의 스케줄링을 담당하여 Java 개발자에게 메모리 관리의 부담을 덜어준다.
GC는 background에서 데몬 쓰레드로 돌며 더이상 사용되지 않는 객체들을 메모리에서 제거하여 효율적인 메모리 사용을 돕는다
객체는 힙 영역 저장되고 스택 영역에 이를 가리키는 주소값이 저장되는데 참조되지 않는(자신을 가리키는 포인터가 없는) 객체를 메모리에서 제거한다.
DNS의 작동원리
DNS 흐름도
설명
1. LocalDNS에 질의 웹 브라우저에 ww.naver.com을 입력하면 먼저 Local DNS에게 "ww.naver.com"이라는 hostname에 대한 IP 주소를 질의 하여 Local DNS에 없으면 다른 DNS name 서버 정보를 받음 (Root DNS 정보 전달 받음)
2. Root DNS에 질의
3. Root DNS 서버로 부터 "com 도메인"을 관리하는 TLD(Top-Level-Domain) 이름 서버 정보 전달 받음
4. TLD에 질의
5. TLD에서 관리하는 DNS 정보 전달
6. naver.com 도메인을 관리하는 DNS 서버에 호스트네임에 대한 IP 주소 질의
7. from 도메인관리 DNS 서버 to Local DNS naver.com 도메인을 관리하는 DNS 서버으로 부터 Local DNS 서버에게 응 naver.com에 대한 IP 주소는 222.122.195.6 응답
8. Local DNS는 naver.com에 대한 IP 주소를 캐싱하고 IP 주소 정보 전달
1. DNS Query (from Web Browser to Local DNS) : "제가 원하는 웹 사이트의 IP 주소를 알고 계신가요?" Local DNS 서버에게 전달
2. DNS Query (from Local DNS to Root DNS) : "제가 원하는 웹 사이트의 IP 주소를 알고 계신가요?" Root DNS서버에게 전달
3. DNS Response (from Root DNS to Local DNS) : "저는 모르지만 , Com 도메인을 관리하는 네임서버의 이름과 IP 주소를 알려드릴 테니 거기에 물어보세요"
4. DNS Query (from Local DNS to com NS) : “ 안녕하세요. www. naver. com의 IP 주소를 알고 계신가요?"
5. DNS Response (from com NS to Local DNS) : "저는 모르지만 , Com 도메인을 관리하는 네임서버의 이름과 IP 주소를 알려드릴 테니 거기에 물어보세요"
6. DNS Query (from Local DNS to naver. com NS) : “ 안녕하세요. www. Naver .com의 IP 주소를 알고 계신가요?"
7. DNS Response (from naver .com NS to Local DNS) : "저는 모르지만 해당 웹은 www. g.naver. com이라는 이름으로 통해요. g.naver .com 도메인을 관리하는 네임서버의 이름과 IP 주소를 알려드릴테니 거기에 물어보세요"
8. DNS Query (from Local DNS to g.naver. com NS) : “ 안녕하세요. www. g.naver. com의 IP 주소를 알고 계신가요?"
9. DNS Response (from g.naver .com NS to Local DNS) : " 네 www. g.naver .com의 IP 주소는 222.222.222.22와 333.333.333.33입니다"
10. DNS Response (from Local DNS to Web Browser) : "네 www. naver .com의 IP 주소는 222.222.222.22와 333.333.333.33입니다"
우아한 테크코드 DNS 설명
DNS탄생
설명
*DNS는 결국 IP주소를 얻어오는 과정이라고 볼 수 있다.
[가정 : idea] 1) User가 dnstest.kr이라는 주소를 알고 있고 자신의 host(sudo vi ~etc/hosts)에 해당 아이피주소를 입력해놨다. 2) 그렇다면 hosts파일을 통해서 IP주소를 얻어와 해당 주소로 3.34.244.232로 접속 가능하다. but 개인이 모든 아이피 값을 hosts에 입력하여 관리할 수 가없다.
*DNS 서버가 그래서 생겼다.
개인User가 hosts값을 모를 때 DNS 서버에 요청하여 IP값을 받아온다.
public DNS서버는 보통 통신사이다. if(통신사가 IP를 알고있다) - 바로 내려준다. 트리형으로 알아간다. else if (통신사가 IP알지 못한다.) -
권한이 없을 때(통신사가 IP알지 못할 때) - Root domain부터 순서대로 질의를 해서 알아간다. (트리형) - 왜 분산해서 트리형으로 조회하나? 서버과부하 방지하기위해
트리형으로 질의를 통해 알아가는 과정
쿠키 / 세션 / 캐시 비교
특징
원리
장점
쿠키
사용자의 브라우저에 저장되고, 통신할 때 HTTP 헤더에 포함되는 텍스트 데이터 파일 이름, 값 만료기간(지정 가능), 경로 정보가 있고 키와 값으로 구성되어 있다 해당 사용자의 컴퓨터를 사용한다면 누구나 쿠키에 입력된 값을 쉽게 확인 가능 -> 보안성이 낮다!
(1) 최초 통신에서는 쿠키값이 없으므로, 일단 클라이언트는 Request 를 한다. (2) 서버에서 클라이언트가 보낸 Request Header에 쿠키가 없음을 판별. 통신 상태(UserID, Password, 조작상태, 방문횟수 등)를 저장한 쿠키를 Response한다. (3) 클라이언트의 브라우저가 받은 쿠키를 생성/보존한다 (4) 두번째 연결부턴, HTTP Header에 쿠키를 실어서 서버에 Request 한다
- 클라이언트는 총 300개의 쿠키를 저장할 수 있음 - 하나의 도메인 당 20개의 쿠키를 가질 수 있음 -> 20개가 넘으면 가장 적게 사용되는 것부터 삭제됨 - 하나의 쿠키는 4KB (4096byte) 저장 가능
자동 로그인 유지, 위시 리스트 저장, 팝업 보지 않기
세션
서버'에 저장되는 쿠키. 클라이언트와 서버의 통신 상태. 주로 중요한 데이터를 저장 시 사용 브라우저를 종료할 때까지 유지 됨 사용자 로컬이 아닌 서버에 직접 저장되므로, 세션 내의 데이터를 탈취하는 것은 어려움 -> 보안성이 비교적 높음
(1) 클라이언트가 서버에 접속 시, 세션 ID를 발급한다. (2) 서버에서는 클라이언트로 발급해준 세션 ID를 쿠키를 이용해서 저장 (3) 클라이언트는 다시 페이지에 접속할 때, 쿠키에 저장된 세션 ID를 서버에 전달 (4) 서버는 Request Header에 쿠키 정보(세션 ID)로 클라이언트를 판별
로그인 정보 유지
캐시
리소스 파일들의 임시 저장소. 같은 웹 페이지에 접속할 때 사용자의 PC에서 로드하므로 서버를 거치지 않아도 된다. 이전에 사용되었던 데이터는 다시 사용될 가능성이 높다 -> 그래서 다시 사용될 확률이 있는 데이터들을 빠르게 접근 가능한 저장소에 저장한다. => 페이지 로딩 속도를 개선함 이미지, 비디오 오디오, CSS/JS 등...
(1) 캐시 히트(Cache Hit) CPU가 참조하려는 메모리가 캐시에 존재하고 있는 경우
(2) 캐시 미스(Cache Miss) <-> 캐시 히트와 반대로, 메모리에 캐시가 존재하지 않는 경우
방식
내용
Local 캐시
- 서버마다 캐시를 따로 저장한다. - 로컬 서버의 리소스를 사용한다. - 서버 내에서 작동하기 때문에 빠르다. - 다른 서버의 캐시를 참조하기 어렵다.
Global 캐시
- 여러 서버에서 캐시 서버를 참조합니다. - 네트워크 트래픽을 사용해야 해서 로컬 캐시보다는 느립니다. - 서버간 데이터 공유가 쉽습니다. - Redis 서버를 사용
LocalCache & GlobalCache
ORM이란?
ORM(Object Relational Mapping) 즉, 객체-관계 매핑의 줄임말이다. 객체-관계 매핑을 풀어서 설명하자면 OOP에서 쓰이는 객체와 RDB(Relational DataBase)에서 쓰이는 데이터인 테이블 자동으로 매핑(연결) 하는 것을 의미한다. 하지만 기존부터 호환가능성을 두고 만들어 진 것이 아니기 때문에 불일치가 발생한다. 이를 ORM을 통해 객체 간의 관계를 바탕으로 SQL문을 자동으로 생성하여 불일치를 해결한다. 즉, 객체 관계 매핑, 객체와 RDB를 별개로 설계하고 ORM이 매핑 해주는 역할이며, ORM은 SQL문이 아닌 RDB에 데이터 그 자체와 매핑하기 때문에 SQL을 직접 잘성할 필요가 없다. 이로인해 어떤 RDB를 사용하던 상관 없다.
MyBatis 마이바티스는 데이터베이스 레코드에 원시타입과 Map 인터페이스 그리고 자바 POJO를 설정하여 매핑하기 위해 XML과 어노테이션을 사용할 수 있다 즉, MyBatis는 자바에서 SQL Mapper를 지원해주는 FrameWork이다. 즉, SQL 작성을 직접 하여 객체와 매핑시켜준다.
SQL Mapper SQL문을 이용하여 RDB에 접근, 데이터를 오브젝트(객체)화 시켜준다. 개발자가 작성한 SQL문으로 해당되는 ROW를 읽어 온 후 결과 값을 오브젝화 시켜 사용가능하게 만들어준다. 즉, RDB에 따라 SQL문법이 다르기 때문에 특정 RDB(작성한 SQL)에 종속적이다.
JPA의 장/단점
장점
RDB에 상관없이 사용가능 -> 재사용성 유지보수 용이
CRUD 기본적인 제공과 페이징 처리 등 상당 부분이 구현되어 있음
테이블 생성, 변경 엔티티 관리가 편하다.
쿼리에 집중할 필요가 없다.
단점
어렵다.
단방향, 양방향, 임베디드 관계 등 이해해야할 내용이 많으며, 연관관계 이해 없이 잘못 코딩 했을 시 성능상의 문제와 동작이 원하는 대로 되지 않는다.
ex) Board 엔티티에 List형태로 Reply 엔티티가 있을 시, 단방향 연관관계인 경우 하나의 Reply가 변경되어도 모두 삭제되고 전부 Insert되는 경우
ex) 하나의 Board 조회 시 Reply를 Join이 아닌 여러개의 select 문으로 하나하나 읽어오는 문제(N+1)
MyBatis의 장/단점
장점
JPA비해 직관적이며 쉽다.
SQL 쿼리를 그대로 사용하기에 Join, 튜닝 등을 좀 더 수월하게 작성 가능하다.
SQL의 세부적인 내용 변경 시 좀 더 간편하다.
동적 쿼리 사용 시 JPA보다 간편하게 구현 가능하다.
단점
데이터 베이스 설정 변경 시 수정할 부분이 너무 많다.
Mapper 작성부터 인터페이스 설계까지 JPA보다 많은 설계와 로직이 필요하다.
특정 DB에 종속적이다.
ORM 프레임워크
- JPA/Hibernate
JPA(Java Persitence API)는 자바의 ORM 기술 표준으로 인터페이스의 모음이다. 이러한 JPA 표준 명세를 구현한 구현체가 바로 Hibernate이다.
사용 예제
프레임 워크
예제
iBatis
Java
Hibernate
JPA Interface : 인터페이스 ↓ 상속 Hibernate, EcipseLink, DataNucleus 등 : 구현체
JPA
ex) 기존쿼리 : SELECT * FROM MEMBER; 이를 ORM을 사용하면 Member테이블과 매핑된 객체가 member라고 할 때, member.findAll()이라는 메서드 호출로 데이터 조회가 가능하다. 만약 Mybatis 였다면 신규 컬럼이 추가 되면 DTO(Vo, Domain), DAO 개발 수정 작업이 매무 반복되어 일어난다. (쿼리 수정, 모델 수정 등...)
Exception은 Checked Exception과 unchecked Exception으로 구분할 수 있는데, 간단하게 RuntimeException을 상속하지 않는 클래스는 Checked Exception, 반대로 상속한 클래스는 unchecked Exception 으로 분류할 수 있다.
가장 중요한 부분은 처리여부이다. RuntimeException을 상속한 클래스를 조금 특별하게 취급한다. 명시적으로 예외처리를 하지 않아도 된다.
Spring에서 어떤 exception에서 롤백처리를 하나?
unchecked Exception의 경우 롤백처리를 하며 스프링의 @transactional 옵션에 rollback가 있는데 디폴트 값이 runtimeException, error이다. 즉 디폴트 값이 runtimeException이므로 롤백된다.
기존 웹 서비스는 요청시마다 서버로부터 리소스들과 데이터를 해석하고 화면에 렌더링하는 방식이다. SPA 형태는 브라우저에 최초에 한번 페이지 전체가 로드하고, 이후부터는 특정 부분만 Ajax를 통해 데이터를 바인딩하는 방식이다.
전통적인 페이지 vs 단일 페이지 어플리케이션 비교
자바스크립트의 발전
초기의 SPA개념 : Backbone.js, Angular.js 라이브러리
지금은 템플릿 개념을 지나 컴포넌트 개념 : React.js, Vue.js
SPA 구현을 쉽게 말하면 jsp파일 없이 index.html파일 하나에 js, css등 리소스 파일들과 모듈들을 로드해서 페이지 이동 없이 특정영역만 새로 모듈을 호출하고 데이터를 바인딩하는 개념이다. 물론 이와 같이 개발하기 위해서는 ES6, Node.js, npm 그리고 webpack 같은 번들러 등 개념을 한번 정도는 잡고 접근해야 할게 많다.
단일 페이지 응용 프로그램 및 사용자 경험
사용자 측면에서 일정한 전체 페이지 새로 고침 혹은 웹사이트에서 정보를 얻기 위해 앞뒤로 왔다갔다 하는 것은 과도한 네트워크 트래픽을 유도하고 편이성 마저 떨어집니다. HTML 버전의 데이터는 모든 여는 태그와 닫는 태그로 인해 일반 JSON 객체와 비교할 때 훨씬 더 크기가 더 크며, 비슷한 페이지를 계속로드하는 경우에는 많은 HTML이 중복됩니다. 또한 두 번째 큰 장점 인 적은 페이지 전체 재로드로 인한 사용자 경험 향상과 더 적은 대역폭이 필요하기 때문에 전반적인 성능 향상이 있습니다.