설명 순서는 다음과 같습니다.

1. 프록시란
2. 객체에서 프록시
3. 프록시 구현
4. Spring에서 프록시 사용하기

1. 프록시란

   - 번역하면 '대리자' 라는 뜻임

   - 클라이언트-서버 개념에서 일반적으로 클라이언트가 서버를 직접 호출하고, 처리 결과를 직접 받는다

   - 그런데 클라이언트가 서버에 직접 요청하는 것이 아니라 어떤 대리자를 통해서 간접적으로 서버에 요청할 수 있음(클라이언트 -> 대리자 -> 서버)

   - 예를 들어 내가 직접 마트에서 장을 볼 수 있지만, 누군가에게 대신 장을 봐달라고 부탁할 수 있다

   - 여기서 이런 대리자를 '프록시' 라고 함

   - 프록시를 사용하면 프록시가 중간에서 여러가지 일을 할 수 있음

      ① 접근 제어 캐싱

         : 엄마에게 라면을 사달라고 부탁했는데, 엄마는 라면이 이미 집에 있다고 할 수 있음. 그러면 기대한 것 보다 빨리 먹을 수 있음

      ② 부가 기능 추가

         : 아빠에게 자동차 쥐유를 부탁했는데, 아빠는 주유뿐만 아니라 세차까지 하고 왔음. 기대한 것외에 세차라는 부가 긴으까지 얻게 되었음

      ③ 프록시 체인

         : 동생에게 라면을 사달라고 부탁했는데, 동생은 또 다른 동생에게 라면을 사달라고 부탁할 수 있음. 중요한 점은 클라이언트는 대리자를 통해 요청했기 때문에 그 이후 과정은 모름. 동생을 통해서 라면이 도착하기만 하면 됨


2. 객체에서 프록시

   - 객체에서 프록시가 되려면, 클라이언트는 서버에게 요청을 한 것인지 프록시에게 요청을 한 것인지 몰라야 함

   - 쉽게 말해서 서버와 프록시는 같은 인터페이스를 사용해야 함. 그렇게 되면 클라이언트가 사용하는 객체를 프록시 객체로 바꾸어도 클라이언트 코드를 변경하지 않아도 됨

   - 프록시의 주요 기능

      ① 접근 제어 : 권한에 따른 접근 차단, 캐싱, 지연 로딩

      ② 부가 기능 추가 : ex) 실행 시간 측정해서 로그 남김


3. 프록시 구현

   - 프록시 핵심 구조

      ① 프록시와 실제 서버는 같은 interface를 구현함 -> 클라이언트가 서버를 호출했는지 클라이언트를 호출했는지 모르게 하기 위해

      ② 프록시는 실제 서버를 필드로 갖고 있어서, 부가적인 일을 수행하는 도중에 실제 서버의 메서드를 호출함


4. Spring에서 프록시 사용하기

   - Controller, Service, Repository의 interface를 구현한 프록시 만들기

   - Bean으로 프록시 객체를 등록해서, 런타임시 클라이언트는 프록시 객체를 사용하도록 함

   - 그러면 프록시 객체를 따로 다 생성해서 Bean으로 등록해줘야 할까? 아님. 

   - Spring은 Java의 Reflection을 이용해서 부가 기능을 추가한 프록시를 동적으로 대신 생성해줌

      * Reflection : 클래스의 메타 정보를 획득해서, 코드를 동적으로 실행시킬 수 있는 기술


프록시에 대해 알아볼 수 있었습니다.

'Spring' 카테고리의 다른 글

AOP (1)  (0) 2023.08.25
IOC(Inversion Of Control), DI(Dependency Injection)  (0) 2023.08.24
[Spring MVC 1편(김영한)] WAS, Servlet이란?  (0) 2023.04.12

설명 순서는 다음과 같습니다.

1. AOP란
2. 문제 예시
3. 템플릿 메서드 패턴으로 해결하기

1. AOP란

   - Aspect Oriented Programming의 약자로 관점 지향 프로그래밍을 뜻함

   - 어떤 로직을 여러가지 관점으로 분리하고 각각의 관점을 모듈화하는 방법을 말함

   - 소스 코드상에서 부가적인 관점은 다른 부분에서 반복해서 사용할 때가 많은데, 이 때 이러한 관점을 한 곳으로 모아서 모듈화를 하고, 재사용하겠다는 취지임

 

2. 예시

   - Controller, Service, Repository의 메소드들의 실행시간을 측정하고 싶다고 가정

   - 코드 : 시작시간 재기 -> 핵심 로직 수행 -> 끝나는 시간 - 시작 시간으로 실행시간 측정

   - 위와 같은 코드를 모든 메소드에 추가해야함

   - 어떻게 줄일까? 이를 해결하는 여러 디자인 패턴부터 스프링의 AOP까지 정리해보자

 

3. 템플릿 메서드 패턴으로 해결하기

   - 템플릿 메서드 패턴의 핵심은 '변하는 것과 변하지 않는 것을 분리' 하는 것임

   - 여기서 변하는 것은 '핵심 로직'이고 변하지 않는 것은 '부가 로직(시간 측정)' 임

   - 그래서 변하지 않는 것을 '템플릿'으로 만들고 변하는 것은 '메서드'로 만들어서 해결하는 방법

   - 구현 : 추상 클래스로 템플릿을 만들고 이 안에 추상 메서드를 만든 후에, 이 클래스를 상속하는 자식 클래스가 자신의 핵심 로직을 추상메서드에 구현하는 방법

   - 변하지 않는 것은 추상클래스의 일반 메서드. 변하는 것은 추상클래스의 추상메서드. 실제 코드로 확인해보자

템플릿
핵심 로직(변하는 부분)
실제 사용

   - 이로써 중복을 줄이고, 관심사를 분리할 수 있음

   - 하지만 템플릿 메서드 패턴은 상속을 사용하고 있는데, 이 때문에 상속에서 오는 단점들을 안고감

   - 자식 클래스(핵심 기능) 입장에서는 부모의 기능을 전혀 사용하지 않는데 강하게 결합되어 있음. 그래서 부모가 변하면 자식에게도 영향을 줄 수 있음


AOP의 기초와 템플릿 메서드 패턴에 대해 알아볼 수 있었습니다.

'Spring' 카테고리의 다른 글

AOP (2)  (1) 2023.08.28
IOC(Inversion Of Control), DI(Dependency Injection)  (0) 2023.08.24
[Spring MVC 1편(김영한)] WAS, Servlet이란?  (0) 2023.04.12

설명 순서는 다음과 같습니다.

1. IOC란
2. IOC 컨테이너
3. DI란
4. IOC와 DI의 핵심

1. IOC란

   - Inversion Of Control의 줄임말로 직역하면 '제어의 반전' 이라는 뜻임

   - 그렇다면 제어가 어떻게 반전됐다는 걸까?

   - 일반적인 프로그램에서 제어권(객체의 생성 및 관리)는 개발자가 직접 해야함

   - 하지만, 스프링 프레임워크를 사용하면 이러한 제어권을 스프링이 갖게 됨

   - 이렇게, 프로그램의 제어권이 개발자에서 스프링이 쥔 것을 IOC라고 함

 

2. IOC 컨테이너

   - 이제 스프링 프레임워크가 제어권을 쥐고 객체의 생성과 관리를 담당함

   - 스프링에서 생성한 객체를 보관하고 관리하는 곳이 IOC 컨테이너임

   - 그리고 이 IOC 컨테이너에 등록되는 객체를 Bean이라고 부르고, 이 Bean들은 싱글톤으로 관리됨

   - 싱글톤 패턴이란

      * 클래스의 인스턴스가 딱 하나만 생성되는 것을 보장하는 디자인 패턴

      * 장점은 서버의 경우 요청마다 객체가 생성되고 소멸될 경우 메모리 낭비가 심한데, 이를 줄여줌

 

3. DI란

   - Dependency Injection의 줄임말로 직역하면 '의존성 주입'이라는 뜻임

   - IOC 컨테이너에서 한 객체를 생성해서 Bean으로 등록하는 과정에서, 그 객체에 필요한 다른 객체를 생성해서 넣어주는 과정이 DI임

   - 쉽게 말하면, 필요한 객체들을 생성한 후에 조립하는 과정이 DI임

 

4. IOC와 DI의 핵심

   - Spring에서 IOC와 DI를 도입한 이유는 프로그램의 제어권을 Spring이 받음으로써 개발자는 온전히 개발에만 집중할 수 있게 하기 위해서임

   - 그래서 개발자는 개발을 담당하고, Spring은 객체의 생성과 관리를 담당

   - 개발자와 프레임워크 사이에 역할을 명확히 나눈 것임


IOC와 DI에 대해 알아볼 수 있었습니다. 

'Spring' 카테고리의 다른 글

AOP (2)  (1) 2023.08.28
AOP (1)  (0) 2023.08.25
[Spring MVC 1편(김영한)] WAS, Servlet이란?  (0) 2023.04.12
프로젝트 구조를 세우자

프로젝트 큰 구조를 세우고 본격적인 구현에 들어가려 합니다.

 

1. 구조

   - 흐름 : 입력 -> 장소 찾기 -> 장소 출력 -> URL 띄우기

   - 도메인 : 사용자 입력 쿼리, 장소

   - 기타 : 예외처리

 

2. 흐름

   (1) 입출력 분리

      - 입력과 출력을 따로 처리하는 클래스를 만들고, 오로지 여기에서만 입출력이 진행됩니다.

      - 입력 -> 장소 찾기 -> 장소 출력 -> URL 띄우기

 

   (2) 장소 찾기 분리

      - 장소 찾기 흐름 : 키워드로 좌표 찾기 -> 좌표로 장소 찾기

      - 위 두가지 모두 Kakao API를 통해 얻어와야하므로, Kakao API 클래스로 분리

      - 이 후, Kakao API 모두 HTTP 통신을 거쳐야하므로, HTTP 통신만을 담당하는 Http 클래스 분리

      - 입력 -> 장소 찾기 -> 장소 출력 -> URL 띄우기

 

   (3) URL 띄우기

      - Desktop 클래스를 이용

      - 메서드로 분리해서 사용

 

3. 도메인

   (1) 사용자 쿼리

      - 필드 : 키워드, 반경(m)

 

   (2) 장소

      - 필드 : 상호명, 주소, 전화번호, URL ...

 

4. 예외처리

   - 각 예외 상황에 맞는 메시지를 같이 던지도록 구현

   - Message는 따로 constant로 분리

 

5. 구현


구현을 완료하여 프로젝트 종료!!!

단순히 구현뿐만 아니라, 구조에 대해서 고민하며 확장성 있는 프로젝트를 만들고 싶었다. 사소한 것까지 많이 고민하다보니 시간은 오래걸렸지만, 나중에 다 자산이 될 것이라고 생각한다. 

과제의 핵심을 구현하자

과제의 핵심은 Kakao API 통신JSON데이터 파싱이라고 생각합니다. 본격적으로 과제 수행 전에 이 두 가지를 확실히 파악하려고 합니다.

 

1. Kakao API 통신

   (1) Kakao API 사용법

      - https://developers.kakao.com/docs/latest/ko/local/dev-guide 여기 링크에 자세한 사용법이 나와있습니다.

      - 간단하게 보면, 요청 헤더에 Kakao에서 받은 API key를 넣고 쿼리 파라미터에 원하는 값을 넣는 방식입니다.

   (2) Java에서 통신하기

      - http통신을 위해 다운로드한 httpcomponents 라이브러리를 사용합니다.

      - 사용방법은 크게 URI 만들기, 요청 메시지 만들기, 결과 받기로 나누어져 있습니다.

 

2. JSON데이터 파싱

   - JSON데이터 파싱을 위해 다운로드한 json 라이브러리를 사용합니다.

   - 사용방법은 JSON String을 JSON Object 또는 JSON Array로 변환하고, 그 안에서 값을 추출하는 것입니다.


 프로젝트 핵심 기능 파악 완료!!!

시작이 반이다

프로젝트 시작전 초기 세팅을 완료하면 절반은 완료했다고 생각합니다. 지금부터 그 절반을 완료하려합니다.

 

1. Github Repository에서 클론 후 프로젝트 열기

   - git clone <repository의 주소>

   - IntelliJ에서 프로젝트 열기

 

2. JDK 세팅

   - IntelliJ의 좌측 상단에 File - Project Structure에서 JDK 11로 세팅

 

3. 프로젝트에 필요한 Library 다운로드

   - json과 httpcomponents 라이브러리 다운로드

   - pom.xml에 다음과 같이 추가

 

4. commit

   - git commit convention에 맞춰서 작성 예정

   - git commit -m "chore : JDK 및 Library 세팅 완료"


프로젝트 절반 완료!!!

코테 준비

1. 백준 5021 - 왕위 계승

: 위상 정렬을 이용해서 풀이. 내 피가 계산되려면 내 부모의 피가 모두 결정되어야하므로, 위상정렬을 이용함

 

2. 백준 14676 - 영우는 사기꾼?

: 건물을 지을 수 있는 경우를 indegree로 판단. 건물이 처음 지어진 경우 자식의 indegree를 줄이고, 마지막 남은 건물이 부서질 경우 자식의 indegree를 올리는 방식으로 풀이. 


오늘 하루도 고생했다!!!

'TIL(Today I Learned)' 카테고리의 다른 글

2023.08.16  (0) 2023.08.16
2023.08.08  (0) 2023.08.08
2023.08.07  (0) 2023.08.07
2023.08.04  (0) 2023.08.04
2023.08.03  (0) 2023.08.03

설명순서는 다음과 같습니다.

1. 인덱스란
2. 해시 테이블을 이용한 인덱스 구현
3. B-Tree를 이용한 인덱스 구현
4. B+Tree를 이용한 인덱스 구현
5. B-Tree계열을 사용하는 이유
6. 항상 index를 사용하는게 좋을까?

1. 인덱스란

   - Data를 빨리 찾기 위해 도와주는 도구

   - <search-key, pointer>로 구성되어 있음. <key, data의 위치>로 보면됨

   - 만약 인덱스가 없다면, 특정 데이터를 찾기 위해서는 DB의 해당 테이블의 모든 데이터를 Full Scan해야 함. 이 때 시간은 O(N)이 걸림

   - 두꺼운 책에서 뒤에 특정 단어를 빨리 찾기 위한 색인과 같은 역할

   - 인덱스를 사용하게 되면

      ① 인덱스를 저장하기 위한 별도의 저장공간이 필요함 -> 아무것이나 인덱스를 사용하면 안됨

      ② INSERT, UPDATE, DELETE시 인덱스 또한 업데이트가 되어야함 -> SELECT문이 자주 사용되는 column에 인덱스를 사용해야함


2. 해시 테이블을 이용한 인덱스 구현

   - 인덱스를 구현하기 위한 방법으로는 여러가지가 있는데, 그 중 하나는 해시 테이블 이용하는 것임

   - 동작방식은 key를 해싱하여 key의 위치를 바로 찾고, 그 값인 data의 위치를 찾아서 data를 찾는 것임

   - 해싱을 통해 O(1) 시간만에 data를 찾을 수 있음(해싱도 최악의 경우는 O(N))

   - 하지만 DB에서는 해시 테이블을 이용해서 인덱스를 잘 구현하지 않는데, 이유는 해시 인덱스는 equal연산에만 특화되어있기 때문임

   - 부등호 연산이 많은 DB 쿼리문같은 경우 해시 인덱스를 전혀 사용할 수 없고 똑같이 Full Scan을 해야함

   - 그렇지만 만약 해당 column에 equal 쿼리문만 들어온다면, 해싱을 사용하는 것이 가장 효율적(MySql은 hashtable로 index를 구성할 수 있도록 지원)


3. B-Tree를 이용한 인덱스 구현

   - B-Tree의 핵심동작은 Binary Search Tree와 비슷함. 둘 다 내가 찾고자 하는 값이 있을 곳만을 탐색하는 것

      * BST의 경우 해당 노드에 하나의 key값이 있고, 내가 찾고자 하는 key가 더 작으면 왼쪽을 탐색, 크면 오른쪽을 탐색하는 것

      * B-Tree는 해당 노드에 여러개의 key값이 있음. 내가 찾고자 하는 key가 여러개의 key의 범위에 해당하는 부분을 탐색하는 것

   - B-Tree는 Balanced Tree로 리프노드의 레벨이 항상 같음. 이 말은 데이터가 삽입, 삭제되더라도 항상 균형을 유지하게끔 추가 작업이 진행된다는 뜻

   - 따라서, B-Tree를 이용했을 때 검색, 삽입, 삭제 모두 O(logN) 시간이 소요

   - 부등호 연산 쿼리에서 사용할 수 있지만, 다음 볼 B+Tree에 비해서 비효율적이라 B+Tree를 DB의 인덱스 구현으로 많이 사용함


4. B+Tree를 이용한 인덱스 구현

   - B+Tree는 B-Tree를 개선시킨 구조

   - B-Tree는 모든 노드에 key에 해당하는 data pointer를 갖고있었는데, B+Tree는 leaf노드에만 data pointer를 갖고 있고 그 외에 노드에는 key만 가지고 있음

   - 그리고 leaf노드들은 모두 linked list로 연결되어있는데, 이 list는 leaf노드가 모두 key에 따라 정렬되어 있기 때문에 범위 연산에 사용하기 매우 용이함. 이유는 40이상 70이하인 값을 찾고 싶다면, 40을 B+Tree에서 찾아 leaf노드에 도달한 후 leaf노드에서 순차적으로 list를 돌며 70이하인 값을 찾으면 되기 때문임

  - 따라서 대부분의 DB는 인덱스를 B+Tree로 구현함


5. Binary Search Tree를 사용하지 않고 B-Tree계열을 사용하는 이유

   - 둘 다 검색, 삽입, 삭제 시 O(logN)의 시간이 소요됨. 그렇다면 왜 굳이 한 노드에 자식이 많은 B-Tree를 사용할까

   - DB는 Disk에 저장되는데, Disk는 저장공간 중 데이터를 가장 많이 저장할 수 있고 가장 느리고 휘발성이 아닌 특징을 갖고 있음. 그리고 DB에서 메모리에 데이터를 올릴 때 블록단위로 올림

   - 이 때 B-Tree계열을 사용하면 BST보다 leaf까지 가는데 level이 작으므로 더 적은 디스크 접근으로 갈 수 있음

   - 디스크 접근 횟수를 줄이기 위해 B-Tree계열을 사용


6. 항상 index를 사용하는게 좋을까?

   - Table크기가 작을 경우, Table에 있는 모든 데이터를 한번에 불러올 수 있는 경우 디스크 접근 횟수는 한번임. 따라서 인덱스를 사용할 때 여러번 있는 디스크 접근 횟수보다 적은 경우 Full Scan 사용

   - 읽어야할 데이터의 건수가 전체 테이블의 20~25%정도를 차지할 경우 Full Scan사용. 이유는 위와 같이 인덱스를 사용하면서 있는 디스크 접근 횟수보다, 모든 데이터를 올리는데 있는 디스크 접근 횟수가 더 적기 때문임


인덱스에 대해서 알아볼 수 있었습니다.

+ Recent posts