TIL - 0706

java-ims

다운로드 기능 수정하기

다운로드 리턴 타입 수정

  • 이전 코드 : AttachmentService에 download를 요청해서 리턴받는 데이터의 타입이 PathResource였음 : PathResource는 프로젝트 패스에 존재하는 파일을 가져오는 API, 특정한 유형의 파일에만 국한된 코드였음

  • 변경하기 : WritableResource로 리턴타입 변경하기 - PathResource의 상위타입(인터페이스), FileSystemResource, FileUrlResource, PathResource의 인터페이스

    • 구체적인 타입이 아닌 확장성을 고려해서 인터페이스와 같은 추상적인 개념을 리턴타입, 파라미터 타입, 필드 타입으로 지정해야함
@GetMapping("/{id}")
    public ResponseEntity<WritableResource> download(@LoginUser User loginUser, @PathVariable Long issueId, @PathVariable Long id) throws IOException {
        .
        .
        .
        
        WritableResource resource = attachmentService.download(loginUser, issueService.findById(issueId), id);
        
        .
        .
        .
        
        return new ResponseEntity<>(resource, header, HttpStatus.OK);
    }

저장한 파일 찾기 역할 다시 지정

  • 이전 코드 : FileManager(abstract class)에서 PathResource를 가져오는 역할까지 다함
    • 문제점 : Local FileManager를 사용하는게 아니라 다른 곳에 파일을 저장한다면? 찾아오는 것 또한 바뀌어야함(코드 변경점이 1곳이 아님)
  • 변경하기 : FileManager는 구현체에게 파일을 찾아오는 일을 위임하고 요청하는 형태로 코드 변경, 리턴 타입은 앞서 WritableResource로 변경
    • 구체적인 방법은 구현체가 각각 알아서 하기때문에 FileSaver를 사용하는 쪽(디펜던시를 가지는 쪽)에서 갈아끼우기만 하면 각각의 전략을 사용할 수 있음 - 코드 변경없이
public abstract class FileManager {
    
    .
    .
    .

    public abstract WritableResource download(String fileManageName);

    protected String getSavePath() {
        return uploadPath;
    }
}

public class LocalFileManager extends FileManager {
    
    .
    .
    .

    @Override
    public WritableResource download(String fileManageName) {
        Path path = Paths.get(getSavePath() + fileManageName);
        return new PathResource(path);
    }
}

/* 파일세이버를 사용하는 쪽 */
public WritableResource download(User user, Issue target, FileSaver fileSaver) {
    if (!uploader.equals(user) || !issue.equals(target)) {
        throw new UnAuthorizedException();
    }
    return fileSaver.download(manageName);
}

도메인 테스트와 통합 테스트 각각하기

  • 어떤 역할을 맡았다고 하면 어떤 역할을 제대로 수행하는지 도메인 테스트(단위)를 꼭 해야함
  • 통합테스트는 전체 서비스 측면에서 클라이언트가 요청을 했을 때 응답의 결과가 예상과 같은지 테스트 : 도메인 테스트로 각각이 통과했다고해도, 객체 간의 협력에 의해 기능이 완성되는데 기대한 응답 결과가 오는지 확인해야함

  • 고로 LocalFileManager를 테스트했어도 AttachmentAcceptanceTest는 해야함

HTTP

어플리케이션 계층 프로토콜

  • TCP/IP 계층 위의 어플리케이션(웹 어플리케이션) 계층에서 사용하는 프로토콜
  • HTTP 1.1과 2의 차이 : 1.1 버젼의 성능 개선 버젼이 2
    • 성능 개선이 이뤄지지않자 구글에서 SPDY(1.1 버젼 개선)을 만들어쓰다 사실상의 표준처럼 사용되자 HTTP 워킹그룹에서 SPDY를 참고해서 작성 : 2 버젼의 가장 큰 목표는 페이지 로드 시간을 줄이는 것(지연 시간 감소)
    • HTTP는 프로토콜이기때문에 프로토콜을 사용(지원)하는 클라이언트, 서버가 있어야함 : 클라이언트(브라우저) 지원은 구글링, 서버는 구현
    • 공부를 해야겠지만 특징을 살펴보면 1 TCP 커넥션 당 1개의 리소스만 응답받는 것이 아니라 1개의 커넥션으로 여러개의 리소스를 응답받을 수 있도록(1.1에서도 파이프라이닝이 있지만 순차적으로 처리하는 방법이라 1개의 리소스 응답 과정에서 시간이 지연될 경우 다음 리소스 응답은 모두 대기상태, 2 버젼에서의 차이는 무엇인지 찾아볼 것 - HTTP HOL blocking 문제로 찾아볼 것), 헤드의 오버헤드를 줄이기위해 압축(이 부분도 압축을 통해 어떤 부분이 나아졌는가 찾아보고 공부하기), 서버 푸시(클라이언트의 요청없이도 서버는 리소스를 응답할 수 있음, 이전에는 서버 푸시를 어떻게 구현했는지도 살펴보기 - 클라이언트 서버 최초 연결만 http로 한 후 ws 프로토콜로 스위칭 한다는 글을 봤음)

jvm

.class와 클래스로더 그리고 메모리 영역과 실행엔진

  • 클래스로더는 컴파일러에 의해 변환된 파일(.class)를 실행가능한 상태로 로드함
    • 메소드 메모리 영역에 클래스 정보를 로드함 : 상수(상수풀), 메소드 정보(입출력 타입, 접근제어자 등), 필드 정보(접근제어자, 이름 등) 등의 정보를 메모리에 로드함
    • 모든 클래스 파일을 로드시키는 것이 아니라 필요할 때 로드함
  • 실행엔진은 메소드 영역에 로드되어있는 클래스 정보를 한 줄 씩 읽어(인터프리터) 실행
    • 메소드 영역의 코드가 실행될 때 사용되는 메모리 영역은 stack(jvm, navive) : 메소드(객체의 메소드) 실행 - 스택 프레임 생성