자바 프로그램 실행 과정

  • 1.자바 소스코드를 컴파일러가 JVM이 이해할 수 있는 코드(byte code)로 변환
  • 2.바이트 코드를 JVM의 클래스 로더에게 전달
  • 3.클래스 로더는 동적로딩(Dynamic loading)을 통해 필요한 클래스들을 로딩 및, 링크하여 런타임 데이터 영역(JVM의 메모리)에 올린다.
    • 클래스 로더 세부 동작 
      • 로드 : 클래스 파일을 가져와서 JVM의 메모리에 로드
      • 검증 : 자바 언어 명세 및 JVM 몇세에 명시된 대로 구성되어 있는지 검사
      • 준비 : 클래스가 필요로 하는 메모리를 할당
      • 분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 래퍼런스로 변경
      • 초기화 : 클래스 변수들을 적절한 값으로 초기화한다. (static 필드)
  • 4.실행엔진(Execution engine)은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행한다. 
    • 자바 인터프리터 : 바이트 코드 명령어를 한줄씩 해석하고 실행  
    • JIT 컴파일러 : 바이트 코드 전체를 컴파일하고 바이너리코드로 변경해서 직접 실행하는 방식
  • 5. 해석된 바이트 코드는 메모리 영역에 배치되어 실질적 수행이 이루어진다. JVM은 필요에 따라 스레드 동기화나 가비지 컬렉션같은 메모리 관리 작업을 수행한다.

 

자바 컴파일러(Java compiler)

  • 자바를 가지고 작성한 자바 소스 코드를 자바 가상 머신이 이해할 수 있는 자바 바이트 코드로 변환한다.
  • javac.exe

 

자바 바이트 코드(Java bytecode)

  • 자바 가상 머신이 이해할 수 있는 언어로 변환된 자바 소스 코드
  • 명령어 크기 1 byte

 

자바 가상 머신(JVM)

  • 자바 바이트 코드를 실행하기 위한 가상 기계
  • 각 운영체제에 맞는 JVM을 설치해야 한다.

 

 

자바 가상 머신 구성요소

  • 자바 인터프리터 : 자바 컴파일러에 의해 변환된 자바 바이트 코드를 읽고 해석하는 역할
  • 클래스 로더(class loader)
    • 자바는 동적으로 클래스를 읽어오기 때문에, 동적으로 클래스를 로딩해주는 역할
  • JIT 컴파일러(Just In Time Compiler)
    • 프로그램이 실행 중인 런타임에 실제 기계어로 변환해 주는 컴파일러
    • 동적 번역을 통해, 프로그램의 실행 속도를 향상시켜 준다.
    • JIT 컴파일러는 자바 컴파일러가 생성한 바이트 코드를 바로 런타임에 기계어로 변환
  • 가비지 컬렉터(Garbage Collector)
    • 더 이상 사용하지 않는 메모리를 자동으로 회수
    • 개발자가 메모리 관리를 하지 않아도 되는 편의성
    • 실행 순서 : 참조되지 않은 객체들 탐색 후 삭제 -> 삭제된 객체의 메모리 반환 -> 힙 메모리 재사용

 


JVM이 관리하는 메모리 구조

  • 자바가 실행되면, JVM은 운영체제로 부터 해당 프로그램을 수행할 수 있도록 필요한 메모리를 할당 받는다.
  • 용도에 따라
    • 1. 메소드(method) 영역
      • 클래스에 대한 정보와 함께 클래스 변수(static variable)가 저장되는 영역
    • 2. 힙(heap) 영역
      • 모든 인스턴스 변수가 저장되는 영역
      • new 키워드를 사용한 인스턴스가 생성되면, 해당 인스턴스의 정보를 힙 영역에 저장한다.
      • 힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.
    • 3. 스택(stack) 영역
      • 메소드가 호출될 때 메소드의 스택 프레임이 저장되는 영역
        • 스택 프레임(stack frame) : 메소드의 호출 정보
      • 메소드가 호출되면, 메소드 호출과 관계되는 지역변수와 매개변수를 스택에 저장
      • 메소드가 호출되면 함께 할당되고, 호출이 완료되면 소멸한다.

 

JVM - Runtime Data Areas

  • JVM이 운영체제 위에서 실행되면서 할당받는 메모리 영역

1. PC 레지스터(register)

  • 프로그램 실행 포인터를 관리하는 영역

 

2. Native method stack(네이티브 메서드 스택)

  • 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역

 

3. Method area

  • Class 자체에 대한 정보
  • Class를 처음 사용하는 시점에 memory에 올라간다.
  • class의 static field

 

4. heap Area

  • new keyword으로 생성되는 모든 인스턴스가 저장된다.
  • String constant pool : string pool을 heap 안에 가지고 있고, 여기에서 문자열을 관리한다.

 

5. call stack area

  • method가 호출되면 method를 위한 공간이 스택에 쌓인다.
  • 그리고 메소드 안에 사용하는 local variable(지역 변수) 같은 것들이 이 공간에 위치한다.

 

자바의 탄생

  • 썬 마이크로시스템즈(Sun Microsystems)에서 제임스 고슬링(James Gosling)이 고안
  • 가전제품에서 사용할 목적으로 만들었지만, 인터넷과 웹의 출현으로 인터넷을 목적으로 개발
  • 제임스 고슬링의 목표 : Write Once, Run Anywhere(한 번 쓰고 어느 곳에서도 실행)

 

자바의 특징

  • 객체지향 언어
    • 객체들을 먼저 만들고, 하나씩 조립, 연결해서 전체 프로그램 완성
    • 객체를 만들기 전, 클래스 작성
    • 캡슐화, 상속성, 다형성
  • 높은 이식성, OS에 독립적
    • 서로 다른 실행환경에서 프로그램을 옮겨 실행 가능
    • 자바 실행환경(JRE)이 설치되어 있는 모든 운영체제에서 실행 가능

  • 인터프리터 언어
    • C언어는 컴파일 언어 // C -> 컴파일 -> machine code
    • Javascript는 인터프리터 언어 // 소스코드 -> (js)엔진 -> 중간코드 생성 -> 한줄씩 machine code
    • 자바 = 컴파일 언어 + 인터프리터 언어
    • ex. Student.java - 컴파일(javac.exe Student.java) - Student.class(byte code)
      • interpret(java.exe) Student 실행 - JVM 기동
      • 1. class loader 호출
      • 2. class file 검사 + 악성코드 check
      • 3. main() 호출 // 없으면 Main method not found

  • 메모리 자동 관리
    • 개발자가 직접 메모리 접근이 불가능하고, 자바가 메모리 직접 관리
    • 객체 생성 시 자동으로 메모리 영역을 찾아서 할당하고, 사용이 완료되면 가비지 컬렉터(Garbage Colletor)를 실행시켜 자동으로 사용하지 않는 객체를 제거한다.
    • 높은 안정성
  • 쉬운 멀티 스레드 구현
    • 자바는 스레드 생성 및 제어와 관련된 라이브러리 API를 제공하기 때문에 운영체제와 상관없이 멀티 스레드를 쉽게 구현 가능하다.
  • 동적 로딩(Dynamic Loading) 지원
    • 실행시 모든 클래스 로딩이 아닌, 필요한 시점에 클래스를 로딩할 수 있는 장점
    • 메모리의 효율적인 사용과 속도를 위해 필요한 클래스를 동적 로딩
  • 분산 환경 지원
    • TCP/IP 라이브러리가 포함되어 있다.
    • http, http 프로토콜을 지원한다.
  • 풍부한 오픈소스 라이브러리
    • 자바는 오픈소스(Open source) 언어이고, 사용하는 라이브러리나 오픈소스의 양이 당야하다.

JRE(Java Runtime Environment) 자바 실행 환경

  • Java class Library + JVM

 

JDK(Java Developement Kit) 자바 개발 도구

  • 유틸리티(개발 도구)
  • JRE + utility
  • JDK 1.1 -> JDK -> 1.2 -> ... -> JDK 1.5(Java5) -> Java6 -> ... -> 자주 사용되는 Java 8과 Java 11
  • 점점 함수형 언어 관련 기능 업데이트 중

 

Java 8

  • 2014년 Java SE 8 업데이트1.
  • 1.람다 표현식(lambda expression) : 함수형 프로그래밍
  • 2.스트림 API(Stream API) : 데이터의 추상화
  • 3.java.time 패키지 : Joda-Time을 이용한 새로운 날짜와 시간 API
  • 4.나즈혼(Nashorn) : 자바스크립트의 새로운 엔진, 성능과 메모리 관리 면에서 개선

 

람다 표현식(labmda expression)

  • 메소드를 하나의 식으로 표현
  • 식별자 없이 실행 가능한 함수 표현식 -> 익명 함수(anonymous function)
  • 클래스와 객체를 생성하지 않아도 메소드 사용 가능
  • 코드의 가독성을 높여준다.
new Thread(new Runnable() {
    public void run() {
        System.out.println("전통적인 방식의 일회용 스레드 생성");
    }
}).start();
 
new Thread(()->{
    System.out.println("람다 표현식을 사용한 일회용 스레드 생성");
}).start();

 

스트림 API(Stream API)

  • 자바에서 많은 양의 데이터 저장에 배열, 컬렉션 사용
  • 배열, 컬렉션 등에 접근하기 위해 반복문이나 반복자(iterator) 사용
  • 가독성과 재사용성 단점, 정형화된 패턴 부재로 데이터마다 다른 방법으로 접근해야 한다는 단점
  • 스트림 API는 데이터를 추상화하여 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 공통된 방법 제공
String[] arr = new String[]{"넷", "둘", "셋", "하나"};
 
// 배열에서 스트림 생성
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(e -> System.out.print(e + " "));
System.out.println();
 
// 배열의 특정 부분만을 이용한 스트림 생성
Stream<String> stream2 = Arrays.stream(arr, 1, 3);
stream2.forEach(e -> System.out.print(e + " "));

 

java.time 패키지

  • JDK 1.1부터 Calendar 클래스 제공. 하지만 문제점이 존재
    • Calendar 인스턴스는 불변 객체가 아니라서 값이 수정될 수 있는 단점
    • 윤초(leap second)와 같은 특별 상황 고려X

 


call by value VS call by reference

  • call by value : 값에 의한 호출
    • 함수 호출 시 전달되는 변수 값을 복사해서 함수 인자로 전달한다.
  • call by reference : 참조에 의한 호출
    • 인자로 전달되는 변수의 래퍼런스를 전달
  • 자바는 call by value으로 값을 넘긴다. 
  • reference type의 경우에는 해당 객체의 주소 값을 복사하여 사용한다.

 

Java Naming rule

  • Class Name : Parscal notation 사용
    • ex. SampleProject
  • Source code Name : (public) class 이름을 따서 만든다.
    • 하나의 java 파일 안에 여러 class가 나올 수 있다. -> public class는 1개

변수의 종류

  • 1. 기본형(primitive type) 변수
    • 실제 연산에 사용되는 변수
    • 자바에서 기본으로 제공해주는 타입들
    • 정수형, 실수형, 문자형, 논리형

 

  • 2. 참조형(reference type) 변수
    • primitive 변수를 이용해서 사용자가 직접 만들어 사용하는 변수
    • 클래스, 인터페이스, 배열, 열거 타입
    • 빈 객체를 의미하는 null 존재

 

접근 제어자(Access modifier)

  • Public
    • (패키지에 상관없이) 제약없이 사용이 가능하다.
  • protected
    • 부모 클래스에서는 public
    • 외부에서는 private
    • 다른 패키지인 경우, 상속 관계 있으면 사용 가능
  • pacakge(default)
    • 키워드를 사용하지 않았을 경우 default로 사용
    • 같은 패키지 이내에서만 사용 가능
  • private
    • 같은 클래스 안에서만 사용 가능
package com.kakao.test;

public class Student {
	// 결론적으로 field는 특별한 이유가 없는 한 싹다 private
	// class 내부의 필드는 보호해야하는 정
	private String stuName; // information hiding
	private String strNum;
	
	public String getStuName() {
		return this.stuName;
	}
	
	/**
	 * @param stuName
	 */
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}
	
	
	public String getStrNum() {
		return strNum;
	}

	public void setStrNum(String strNum) {
		this.strNum = strNum;
	}

	public Student(){
		
	}
	// method는 행위를 하는 작업이기 때문에 특별한 이유가 없는 한 
	// 외부에서 사용할 수 있도록 public으로 설정한다. 
}

 


래퍼 클래스(Wrapper Class)

  • Primitive(기본 타입) type의 데이터를 객체로 취급해야 하는 경우가 생길 때 사용
  • 기본 타입 데이터를 객체로 포장해주는 클래스
  • 래퍼 클래스는 인스턴스에 저장된 값을 변경할 수 없기 때문에, 새로운 인스턴스 생성 후 생성된 인스턴스 값만 참조 가능
  • 박싱(Boxing) : 기본 타입 데이터를 래퍼 클래스의 인스턴스로 변환하는 과정
  • 언박싱(UnBoxing) : 래퍼 클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정
  • JDK 1.5부터 컴파일러가 자동으로 박싱, 언박싱 처리 -> 오토 박싱, 오토 언박싱

 


제너릭(generic)

  • 데이터의 타입(data type)을 일반화(generalize) 하는 것
  • 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법
    • 객체의 타입 안정성 증가
    • 반환 값에 대한 타입 검사 비용 절감
  • JDK 1.5 이전까지는 Object를 사용했기 때문에, 원하는 타입으로 변환할 때 오류 발생 가능성이 있었다.
  • 제네릭 도입 이후 타입 변환과 같은 번거로운 작업 생략 가능
  • 타입 변수(type variable) : 임의의 참조형 타입을 의미한다.
    • 제네릭 클래스를 생성할 때, 타입 변수 자리에 사용할 실제 타입 명시 필요
    • 타입 변수 자리에는 기본 클래스가 아닌, 래퍼 클래스를 사용
    • Java SE 7부터는, 타입 추정이 가능한 경우, 타입 생략 가능
MyArray<Integer> myArr = new MyArray<Integer>();
MyArray<Integer> myArr = new MyArray<>();
import java.util.*;

class LandAnimal { public void crying() { System.out.println("육지동물"); } }
class Cat extends LandAnimal { public void crying() { System.out.println("냐옹냐옹"); } }
class Dog extends LandAnimal { public void crying() { System.out.println("멍멍"); } }
class Sparrow { public void crying() { System.out.println("짹짹"); } } 

class AnimalList<T> {
	ArrayList<T> al = new ArrayList<T>();
	
	void add(T animal) { al.add(animal); }
	T get(int index) { return al.get(index); }
	boolean remove(T animal) { return al.remove(animal); }
	int size() { return al.size(); }
}

public class prog {
	public static void main(String[] args) {
		AnimalList<LandAnimal> landAnimal = new AnimalList<>();	// Java SE 7부터 생략가능함.
		
		landAnimal.add(new LandAnimal());
		landAnimal.add(new Cat());
		landAnimal.add(new Dog());
		// landAnimal.add(new Sparrow());	// 오류가 발생함.
		
		for (int i = 0; i < landAnimal.size() ; i++) {
			landAnimal.get(i).crying();
		}
	}
}

 


컬렉션 프레임워크(Collection Framework)

  • 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합
  • 데이터를 저장하는 자료구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것
  • 인터페이스를 사용하여 구현
    • List, Set, Map

 

 

스트림(Stream)

  • 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림이라는 흐름 사용
  • 실제 입력이나 출력이 표현된 데이터의 이상화된 흐름
  • java.io 
    • InputStream
    • OutputStream
  • 보조 스트림 : 실제 데이터를 주고받지는 않지만, 다른 스트림의 기능을 향상시키거나 새로운 기능을 추가
    • 여러 개 Stream을 결합해서 확장 가능 

 

람다 표현식(lambda expression)

  • 메소드를 하나의 식으로 표현한 것
  • 객체를 생성하지 않아도, 메소드 사용 가능
  • Java SE 8 부터 람다 표현식이 생겼고, 함수형 프로그래밍 가능
  • 유의사항
    • 매개변수 타입의 추론이 가능한 경우 생략 가능
    • 매개변수가 하나일 때 괄호 생략 가능
    • 함수의 몸체가 하나의 명령문일 때 중괄호 생략 가능
    • 함수의 몸체가 하나의 return 문일 때 중괄호 생략 불가능 
    • return문 대신에 표현식 사용 가능
int min(int x, int y) {
    return x < y ? x : y;
}

// lambda expression
// (매개변수 목록) -> {함수 몸체}
(x, y) -> x < y ? x : y;
new Thread(new Runnable() {
    public void run() {
        System.out.println("전통적인 방식의 일회용 스레드 생성");
    }
}).start();
 
new Thread(()->{
    System.out.println("람다 표현식을 사용한 일회용 스레드 생성");
}).start();

 

 

함수형 인터페이스(functional interface)

  • 람다 표현식을 하나의 변수에 대입할 때 사용하는 참조 변수의 타입
  • 추상 클래스와 다르게, 하나의 추상 메소드만 가진다.
  • 어노테이션을 사용해 함수형 인터페이스 명시
@FunctionalInterface
interface Calc { // 함수형 인터페이스의 선언
    public int min(int x, int y);
}
 
public class Lambda02 {
public static void main(String[] args){
        Calc minNum = (x, y) -> x < y ? x : y; // 추상 메소드의 구현
        System.out.println(minNum.min(3, 4));  // 함수형 인터페이스의 사용
    }
}

 

스트림 API

  • Java SE 8부터 생긴 개념
  • 배열이나 컬렉션에 접근하기 위해서는 반복문이나 반복자(iterator)를 사용해야 한다. -> 가독성 저하, 코드 재사용 불가능
  • 정형화된 데이터의 단점을 스트림 API은 데이터를 추상화해서 다뤄 다양한 방식으로 저장된 데이터를 읽고 쓰기 가능하다.
  • 스트림 API 특징
    • 외부 반복을 통해 작업하는 컬렉션과 다르게 내부 반복을 통해 작업 수행
    • 재사용이 가능한 컬렉션과 다르게 한 번 사용 가능
    • 원본 데이터 변경 X
    • 연산은 필터-맵(filter-map) 기반의 API를 사용해서 성능 최적화
    • parallelStream() 메소드를 통해 손쉬운 병렬 처리 지원
  • 동작 흐름
    • 1. 스트림의 생성
    • 2. 스트림의 중개 연산 (스트림의 변환)
    • 3. 스트림의 최종 연산 (스트림의 사용)

 

Optional Class

  • primitive 타입의 객체를 포장해주는 래퍼 클래스
  • Optional 인스턴스는 모든 타입의 참조 변수를 저장할 수 있다.
  • 예상치 못한 NullPointerException 예외를 제공되는 메소드로 간단히 회피 가능
  • null 값 예외 처리 가능

 

Optional 객체 생성

  • of() 메소드 : null 이 아닌 명시된 값을 가지는 Optional 객체 반환
  • ofNullable() 메소드 사용 
    • 명시된 값이 null이 아니면 명시된 값을 가지는 Optional 객체를 반환하고, 명시된 값이 null이면 비어있는 Optional 객체 반환 
    • null 가능성이 있을 때 사용

디자인 패턴

  • 객체지향 프로그래밍 설계를 할 때 자주 발생하는 문제들을 피하기 위해 사용하는 패턴
  • 목적
    • 재사용성, 호환성, 유지보수성
  • 원칙 - SOLID(객체지향 설계 원칙)
    • Single Reponsibility Principle(SRP) : 하나의 클래스는 하나의 동작만
    • Open - Close Principle : 확장(상속)에는 열려있고, 수정에는 닫기
    • Liskov Substitution Principle : 자식이 부모의 자리에 항상 교체될 수 있어야 한다.
    • Interface Segregation Principle : 인터페이스가 잘 분리되서, 클래스가 꼭 필요한 인터페이스만 구현하도록 제어
    • Dependency Inversion Property : 상위모듈이 하위 모듈에 의존적 X. 둘 다 추상화에 의존해야 한다.

 

디자인 패턴의 3가지 분류

1. 생성 패턴 : 객체의 생성 방식 결정

  • 싱글톤 패턴(Singleton)
    • 하나의 인스턴스만 사용할 수 있도록 객체를 생성하는 방법
    • 객체가 여러 번 생성되지 않고, 최초 하나의 인스턴스만 생성 후 이 인스턴스만 참조하게 된다.
    • 커넥션 풀, 스레드 풀, 디바이스 설정 객체 등의 경우 인스턴스를 여러 개 만들게 되면 자원을 낭비하게 된다.
    • 버그를 발생시킬 수 있는 위험으로 오직 하나만 생성하고 그 인스턴스를 사용하는 것이 목적

public class Singleton {
    private static Singleton singletonObject;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singletonObject == null) {
            singletonObject = new Singleton();
        }
        return singletonObject;
    }
}
  • 멀티 스레드 환경에서는 싱글턴 패턴을 사용하다가 동시 접근을 해야 하는 상황이 생길 경우, 인스턴스가 두 개 생성될 위험이 잇다. synchronzied 사용
  • 동기화 사용 : 멀티 코어에서  하나의 CPU를 제외한 다른 CPU가 Lock에 걸릴 위험이 있다.
  • 사전 초기화 : 클래스 로딩 시점에 미리 객체를 생성하고, 그 객체를 반환한다.
    • volatile 키워드 사용 : 캐시에 저장된 값 X -> main memory 값 사용
    • 메모리 효율이냐 연산 효율은 사후 초기화보다 낮다.
public class Singleton {
    private static volatile Singleton singletonObject = new Singleton();

    private Singleton() {}

    public static Singleton getSingletonObject() {
        return singletonObject;
    }
}

 

 

  • 프로토타입 패턴(Prototype)
    • 기존의 인스턴스를 그대로 복제(clone)해서 새로운 객체를 생성하는 기법
    • 싱글톤과 반대의 개념
    • 데이터베이스에서 받아온 데이터 인스턴스를 하나 더 만들어야 하는 경우 사용

 

  • 팩토리 패턴(Factory)
    • 인스턴스를 만드는 공장(Factory)를 통해 객체를 생성하는 방법
    • 인스턴스를 직접 생성하지 않고, 객체 반환 함수를 (생성자 대신) 제공
    • 초기화 과정을 외부에서 보지 못하게 숨기고 반환 타입을 제어할 수 있다.
    • 비슷한 분류의 클래스들의 생성을 모아 처리하는게 편한 경우 사용

 

  • 추상 팩토리(Abstract Factory)
    • 공장을 만드는 상위 공장을 먼저 정의한다.
    • 많은 수의 연관된 서브 클래스를 특정 그룹으로 묶어 한 번에 교체할 수 있다.

 

  • 빌더(Builder)
    • 객체를 생성할 때 필요한 파라미터가 많은 경우, 인스턴스를 생성자를 통해 직접 생성하지 않고 빌더라는 내부 클래스로 간접적으로 생성하게 하는 패턴
    • 클래스와 사용 대상의 결합도를 낮추기 위해 사용
    • 생성자에 전달하는 인수에 의미를 부여하기 위해 사용

 

2. 구조 패턴 : 객체간의 관계를 조직

  • 어댑터 패턴(Adapter)
    • 서로 다른 클래스의 인터페이스를 연결하고자 사용하는 패턴
    • 인터페이스는 바뀌어도, 변경 내역은 어댑터에 캡슐화 되어 클라이언트는 바뀔 필요가 없다.
    • ex. 110V -> 220V 플러그

 

  • 컴포지트 패턴(Composite)
    • 객체의 hierarchies(계층) 표현
    • 각각의 객체를 독립적으로 동일한 인터페이스를 통해 처리할 수 있게 한다.
    • 여러 개의 클래스가 크게 보면 같은 요소(Component)에 속하지만, 여기에 속한 어떤 클래스(Composite)가 자신이나 다른 클래스(Leaf)를 가질 수 있는 구조
    • 트리 형태의 클래스
    • 데코레이터와 비교
      • 데코레이터 패턴 : 객체가 상황에 따라 다양한 기능이 추가되거나 삭제되어야 할 경우(크리스마스 트리 장식)
      • 공통점 : composition이 재귀적으로 발생
      • 차이점 : 데코레이터 패턴은 responsibilityes를 추가하는 것이 목적
        • composite 패턴은 계층구조를 표현하기 위해서 사용

 

  • 프록시(Proxy) 패턴
    • 연산을 스스로 객체가 직접 처리하는 것이 아니라, 숨겨진 객체를 통해 처리하는 방법
    • 구체적 업무 담당 클래스 접근 전에, 간단 사전 작업 처리 클래스(Proxy)를 두는 구조

 

 

3. 행위 패턴 : 객체의 행위를 조직, 관리, 연합

  • 스트레티지(Strategy) 패턴
    • 어떤 동작을 하는 로직을 정의하고, 이것들을 하나로 묶어(캡슐화) 관리하는 패턴
    • 새로운 로직을 추가하거나 변경할 때, 한 번에 효율적으로 변경이 가능하다.
    • 미사일 쏘기, 폭탄 사용 캡슐화
    • 전투기와 헬리콥터를 묶을 Unit 추상 클래스 생성
[ 슈팅 게임을 설계하시오 ]
유닛 종류 : 전투기, 헬리콥터
유닛들은 미사일을 발사할 수 있다.
전투기는 직선 미사일을, 헬리콥터는 유도 미사일을 발사한다.
필살기로는 폭탄이 있는데, 전투기에는 있고 헬리콥터에는 없다.

 

  • 템플릿 메소드(Template Method) 패턴
    • 로직을 단계 별로 나누어야 하는 상황에서 사용한다.
      • 상위 클래스가 뼈대
      • 하위 클래스가 각각 로직 구현
    • 단계별로 나눈 로직들이 앞으로 수정될 가능성이 있을 때 효율적이다.
    • 조건
      • 클래스는 추상 클래스로 만든다. -> 자식 클래스에서 선택적 메소드 오버라이딩 가능
        • abstract : 부모의 기능을 자식에서 확장시켜나가고 싶을 때
        • interface : 해당 클래스가 가진 함수의 기능을 활용하고 싶을 때
      • 단계를 진행하는 메소드는 수정이 불가능하도록 final 키워드 사용
      • 각 단계들은 외부는 막고, 자식들만 활용 가능하도록 protected 으로 선언
    • 예시 (반죽 -> 토핑 -> 굽기)
      •  피자 종류에 따라 토핑만 바꿔준다.

 

  • 옵저버(Observer) 패턴
    • 서로의 정보를 주고 받는 과정에서 단위가 크면, 객체 규모가 크면 복잡성 증가
    • 객체의 변경은 복잡한 코드에서 객체의 변경 추적을 어렵게 한다.
    • 객체의 변경을 추적하기 위해 옵저버 패턴을 사용하여 객체를 참조하는 모든 이들에게 변경 사실을 알리고 대처하는 추가 대응이 필요하다.
    • 인터페이스를 통해 연결하여 느슨한 결합성을 유지하고, Publisher와 Observer 인터페이스 적용

 

아파치 카프카(Apache Kafka)

  • 아파치 소프트웨어 재단이 슼라라로 개발하나 오픈 소스 메시지 브로커 프로젝트
  • 실시간 데이터 피드를 관리하기 위해 통일된, 높은 처리량, 낮은 지연시간을 지닌 플랫폼을 제공하는 것이 목표
  • 분산 트랜잭션 로그로 구성된, 확장 가능한 pub/sub 메시지 큐로 정의 가능
  • 스트리밍 데이터를 처리하기 위한 기업 인프라를 위해 적절하다.

 

pub/sub 모델(발신자/수신자)

  • 발신자 : 카프카에게 토픽(Topic)이라는 주소로 전송하는 역할
  • 수신자 : 카프카에게 원하는 토픽을 구독

 

개발 배경

  • 기존 링크드인 데이터 처리 시스템은 각각의 파이프라인 별 dependency가 높았고, 확장하기 어려운 상황이였다.
  • 카프카 개발 전 링크드인 데이터 처리 시스템

  • 카프카 적용
    • 프로듀서와 컨슈머의 분리
    • 영구 메시지 데이터를 여러 컨슈머에게 적용
    • 높은 처리량을 위한 메시지 최적화
    • 트래픽 증가에 따른 스케일 아웃이 가능한 시스템

 

 

카프카 구성 요소

  • 프로듀서(Producer) : 메시지를 생산하고, 브로커의 토픽으로 전달하는 역할
  • 컨슈머(Consumer) : 브로커의 토픽으로부터 저장된 메시지를 가져오는 역할
  • 브로커(Broker) : 카프카 내의 서버 또는 노드를 지칭한다. -> 실행된 카프카 서버. 메시지를 저장하고 관리한다.
  • 주키퍼(Zookeper) : 분산 어플리케이션 관리를 위한 코디네이션 시스템
    • 분산된 노드 정보(메시지 큐의 메타 정보) 중앙 처리 및 구성 관리, 동기화 등을 수행한다.

 

 

카프카 동작 방식

  • 프로듀서는 메시지를 카프카에 전달한다.
  • 전달된 메시지는 브로커의 토픽(Topic)이라는 구분에 의해 저장된다.
  • 컨슈머는 구독한 토픽에 접근하여 pull 방식으로 가져온다.

 

 

카프카의 특징과 장단점

  • 특징과 장점
    • 디스크에 메시지를 저장해서 영속성(persistency) 보장
    • 프로듀서와 컨슈머 분리로 멀티 프로듀서와 멀티 컨슈머 지원 -> pub/sub 구조의 확장성
    • 메시지 배치 처리가 가능해서 네트워크 오버헤드 감소
    • 높은 성능과 고가용성, 확장성 : 일부 노드가 죽어도 다른 노드가 일을 지속
    • 메시지 보장 여부 선택 가능
  • 단점
    • 직접 통신이 아니기 때문에 잘 전달됬는지 파악 X
    • 중간 메시징 플랫폼을 거쳐서 전달 속도가 상대적으로 느리다.

 

쿠키(Cookie)

  • 인터넷에 접속할 때 웹 사이트가 있는 서버에 의해 사용자의 컴퓨터에 저장되는 정보
  • 주로 로그인 정보, 장바구니 정보를 저장한다.
  • 쿠키와 다르게 캐시는 사운드, 이미지 파일을 일시적으로 저장해서 로딩을 빠르게 하는 것
  • 기존에 쿠키는 암호화가 되지 않았지만, 최근에는 암호화가 이루어져서 과거처럼 매우 낮은 보안성을 가지지 않는다.
  • 쿠키는 최적화 프로그램으로 자주 삭제하거나 브라우저의 자동 삭제 기능을 사용한다.
  • 쿠키를 차단할 수 있지만, 차단하면 사이트가 동작하지 않을 수 있는 단점이 있다.

 

세션(Session)

  • 쿠키를 기반으로 일정 시간동안 같은 브라우저로부터 들어오는 요구를 하나의 상태로 보고 그 상태를 유지하는 기술
  • 쿠키는 클라이언트
  • 세션은 웹 서버에 저장
  • 둘 이상의 통신 장치나 컴퓨터와 사용자 간의 대화나 송수신 연결상태를 의미하는 시간대
  • 세션은 연결상태 유지보다, 안정성이 더 중요하다.

 

쿠키 vs 세션

  • 쿠키
    • 클라이언트에 저장, 파일로 관리되기 때문에 브라우저의 종료와 상관없이 만료시간까지 존재
    • 관련 정보들이 쿠키 내부에 존재해서 빠른 속도 
    • 클라이언트가 서버로 요청을 보낼 때 요청 메시지를 스나이핑 당할 위험이 있다.
  • 세션
    • 서버에 저장되어 브라우저 종료 혹은 세션 만료시간 이후 삭제된다.
    • 관련 정보들이 서버에 저장되서 느린 속도를 가진다.
    • 세션은 쿠키를 통해 세션 Id만 저장하고 나머지 정보는 서버에 처리해서 상대적으로 보안성을 갖고 있다.

 

  쿠키(Cookie) 세션(Session)
저장위치 클라이언트(Client) 서버(Server)
저장형식 Text Object
만료시점 쿠키 저장시 설정 설정 시간
리소스 클라이언트의 리소스 서버의 리소스
용량제한 한 도메인 당 20개, 한 쿠키당 4KB 제한 없음

 

저장 위치 

  • 쿠키 : 클라이언트의 웹 브라우저가 지정하는 메모리나 하드디스크
  • 서버 : 서버의 메모리

 

만료 시점

  • 쿠키 : 저장할 때 expires 속성을 정의한다.
  • 세션 : 클라이언트 로그아웃 or 설정 시간 -> 정확한 시점을 알 수 없다.

 

리소스

  • 쿠키 : 클라이언트에 저장, 서버 자원 사용 X
  • 세션 : 서버에 저장, 서버 메모리에 로딩되고 세션이 생길 때마다 리소스 차지

 

용량 제한

  • 쿠키 : 쿠키로 인해 문제가 발생하는 것을 방지하고자 한 도메인당 20개, 한 쿠키당 4KB
  • 세션 : 클라이언트가 접속하면 서버에 의해 생성된다. -> 제한 없음

 

만약 로드밸런서와 세션을 사용한다면?

  • 세션은 서버에 저장된다. 
  • 여러 서버가 분산되어 있고, 로드밸런서를 사용할 때 세션은 공유되지 않는다.
  • 클라이언트가 로그인을 위해 서버A에 요청을 보내면 서버 A의 세션 저장소에 저장된다.
  • 클라이언트가 서비스를 이용하기 위해 서버B에 요청을 보내면 서버 B에는 해당 클라이언트의 세션 정보가 없기 때문에 로그인 페이지로 리다이렉트 하는 문제 발생
  • 해결 방법
    • Sticky Session
      • 첫 요청에 대한 응답을 준 서버에게 sticky하게 붙어서 이후의 모든 요청들을 해당 서버로만 보내는 방법
      • 단점 : 로드 밸런성 효율 저하
    • Session Clustering(세션 클러스터링)
      • 여러 대의 서버를 하나의 서버처럼 운영한다. 각 서버의 세션 저장소를 하나로 묶어서 관리한다.
      • 모든 서버가 동일한 세션을 공유하게 되기 때문에 하나의 서버가 죽어도 세션 정보를 잃어버릴 위험이 없어진다.
      • 단점 : 모든 세션 저장소 업데이트, 메모리 필요 -> 성능 저하
    • Session Server
      • 세션만 관리하는 별도의 서버를 두는 방식
      • 모든 서버의 업데이트 필요 X, Redis같은 In-memory(인메모리) 데이터 저장소를 사용해서 빠른 세션 조회 가능
      • 단점 : 하나의 세션 서버로 관리하기 때문에 서버가 죽으면 모든 세션 데이터를 잃어버린다.
        • 하지만 레디스를 사용하면 다른 서버의 메모리에 실시간으로 복사본을 저장하거나 디스크에 직접 저장하여 백업 가능
        • Master-Slave 형식으로 서비스 유지 가능
        • 단점 : 데이터 별도 저장의 메모리 필요

HTTP(HyperText Transfer Protocol)

  • HTTP -> TCP
  • 인터넷에서 클라이언트와 웹 서버가 자원을 주고 받을 때 사용하는 통신 규약
  • HTTP 1.1 : connection 당 하나의 요청 처리 -> 동시 전송의 문제
  • HTTP 2.0 : 서버로부터 여러 파일을 병렬적으로 전송하기 때문에, 속도 개선이 가능하다.
  • 클라이언트 요청과 서버의 응답에 필수 적인 정보인 ‘헤더’ 
    • 데이터 중복 전송을 방지
    • 데이터를 압축해서 전송하기 때문에 서버와의 통신으로 인해 발생하는 전송 트래픽을 절감할 수 있다.
  • 필요한 리소스를 클라이언트가 요청하기 전에 서버에서 먼저 전송할 수 있는 ‘서버푸시’ 기능도 새롭게 도입되어서 불필요한 통신 과정을 없앴다.
  • REST API는 HTTP 통신으로 이루어진다.
  • 단점
    • 통신 상대를 확인하지 않아서 모르는 사람에게서도 요청이 오면 무조건 응답을 한다.
    • 이를 보완하기 위해서 SSL 사용 -> SSL은 증명서를 이용해서 상대를 확인할 수 있다.

 

HTTPS(HyperText Transfer Protocol Secure)

  • HTTPS -> SSL -> TCP
  • 인터넷에서 정보를 암호화하는 SSL 프로토콜을 사용해서 클라이언트와 서버가 자원을 주고 받을 때 쓰는 통신 규악
    • SSL(Secure Socket Layer) or TLS(Transport Layer Security)
    • 암호화되지 않은 HTTP, 암호회된 HTTPS

  • 텍스트를 공개키 암호화 방식으로 암호화한다.
  • 통신 흐름
    • A 기업은 HTTPS을 적용하기 위해 공개키, 개인키 생성
    • 신뢰할 수 있는 CA 기업 선택 후, 공개키 관리를 부탁한다. (CA : Certifiacte Authority)
    • CA 기업은 공개키, 공개키 암호화 방법을 담은 인증서를 만들고, 인증서로 CA 기업의 개인키로 암호화해서 A 서버에게 제공
    • A 서버는 암호화된 인증서를 갖게된다. A 서버는 공개키로 암호화된 요청이 오면, 암호화된 인증서를 클라이언트에게 준다.
    • CA 기업의 공개키는 브라우저가 이미 알고 있기 때문에 브라우저는 암호화된 인증서를 해독하고 A 서버의 공개키를 얻게 된다.
    • A 서버와 통신할 때 얻은 A 서버의 공개키로 암호화해서 요청이 가능해진다.

 

대칭키(Symmetric Key)

  • 암호화와 복호화에 같은 암호키(대칭키)를 사용하는 알고리즘
  • 키를 하나만 사용하기 때문에 빠르다.
  • 하지만 해킹 위험이 있다.

 

공개키(Public Key), 비대칭키(Asymmetric Key)

  • 대칭키 키 분배 문제를 해결하기 위해 생긴 개념
  • 고유 암호키(비밀키)를 사용해서 복호화할 수 있는 암호키(공개키)를 공개해서 사용

 

SSL - 대칭키 + 공개키 암호화 방식

  • A가 웹 상에 공개된 B의 공개키로 암호화 통신에 사용할 대칭키를 암호화해서 B에게 보낸다.
  • B는 자신의 비밀키로 복호화 한다.
  • B는 A로부터 얻은 대칭키로 A에게 보낼 평문을 암호화해서 A에게 보낸다.
  • A는 자신의 대칭키로 암호문을 복호화한다.

TCP와 UDP

  • TCP(Transmission Control Protocol)
    • 신뢰성 있는 바이트 스트림 전송
    • 송신자와 수신자가 소켓이라고 부르는 종단점을 생성한다.
    • 3-way handshake 으로 연결 설정
    • 전이중(full-duplex), 점대점(point to point) 방식
    • 멀티캐스팅, 브로드캐스팅을 지원하지 않는다.
  • UDP(User Datagram Protocol)
    • 비연결형 프로토콜
    • 흐름제어, 오류제어 또는 손상된 세그먼트의 수신에 대해 재전송 X

 

GET과 POST

  • GET
    • HTTP Request Message의 Header에 URL이 담겨서 전송
    • query string : ? 뒤에 데이터가 붙어 request
    • 제한적인 크기
    • URL에 데이터가 노출된다.
  • POST
    • HTTP Request Message의 Body에 데이터가 담겨서 전송
    • 보안이 필요한 데이터는 POST가 더 낫다. -> 패킷 스니핑 위험으로 완전하지는 않다.

OSI 7 계층

 

1. 물리(physical)

- 리피터, 케이블, 허브

- 전기적인 신호로 변환해서 주고받는 기능을 진행하는 공간

- 데이터의 전송

 

2. 데이터 링크(Data link)

- 브릿지, 스위치

- 물리 계층으로 송수신되는 정보를 관리해서 안전하게 전달되도록 도와주는 역할

- MAC 주소로 통신

- 흐름제어, 에러검출, 재전송

 

3. 네트워크(Network)
- 라우터, IP

- 데이터를 목적지까지 가장 안전하고 빠르게 전달하는 기능 담당

- 라우터를 통해 이동할 경로를 선택하여 IP 주소를 지정하고, 해당 경로에 따라 패킷 전달

- 라우팅, 흐름제어, 오류제어, 세그멘테이션

 

4. 전송(Transport)

- TCP, UDP

- 프로토콜을 통해 통신 활성화. 프로그램들이 전송을 할 수 있도록 제공

- TCP : 신뢰성, 연결지향적

- UDP : 비신뢰성, 비연결성, 실시간

 

5. 세션(Session)

- API, Socket

- 데이터가 통신하기 위한 논리적 연결 담당

 

6. 표현(Presentation)

- JPEG, MPEG

- 데이터 표현에 대한 독립성을 제공하고 암호화하는 역할

- 파일 인코딩, 명령어 포장, 압축, 암호하ㅗ

 

7. 응용(Application)

- HTTP, FTP, DNS

- 응용 프로세스와 직접 관계하여 일반적인 응용 서비스를 수행

- 사용자 인터페이스, 전자우편, 데이터베이스 관리 등의 서비스 제공

'CS > 네트워크' 카테고리의 다른 글

[네트워크] 동기 vs 비동기, 블로킹 vs 논블로킹  (0) 2022.10.04

SQL Injection

  • 클라이언트의 입력 값을 조작하여 서버의 데이터베이스를 공격할 수 있는 보안 공격방법
  • 사용자의 입력 데이터를 제대로 필터링 하지 않을 경우 발생
  • ex. 'OR '1' = '1' 으로 아이디와 비밀번호가 올바르지 않아도 로그인
SELECT user FROM user_table WHERE id='admin' AND password=' ' OR '1' = '1';

 

방어 방법

  • 유저에게 받은 값을 바로 SQL에 넘기지 않는다.
  • input 값을 받고, 특수 문자 여부 검사
  • SQL server 오류 발생 시, 에러 메시지 감추기
    • view를 활용하고, 원본 DB 접근 권한 높이기
  • 요즘 사용하는 DB들은 유저 입력이 의도치 않은 동작을 하지 않도록 escape 함수와 prepared statement 제공
    • prepared statement : 변수를 문자열로 바꾸는 것. 특수 문자를 자동으로 escape
    • statement와 다르게 쿼리문의 전달 값을 ?으로 받는다. 서버 측에서 필터링 후 공격 방어

 

prepared statement 

  • 준비(prepare) : 먼저 애플리케이션에서 문의 틀을 만들고, DBMS에 보낸다.
    • 특정 값은 지정하지 않은 채로 남겨지고, 이 값들을 '변수', '플레이스홀더', '바인드 값'으로 부른다.
  • 그 후에 DBMS에서 문의 틀을 컴파일 하고, 결과만 저장한다.
  • 실행(Excute) : 나중에 애플리케이션에서 바인드 값을 지정하면, DBMS은 결과를 반환할 수도 있는 문을 실행한다. 
INSERT INTO product (name, price) VALUES (?, ?);

 

Java JDBC 예시

import java.sql.PreparedStatement;

PreparedStatement pstmt;
String sql = "INSERT INTO usertbl VALUES (?, ?)";
pstmt = con.prepareStatement(sql);

pstmt.setString(1, 'userId123'); // userId
pstmt.setInt(2, 010-1234-5678) // phoneNum
pstmt.executeUpdate();

+ Recent posts