반응형

개요

실무에 필요한 HTTP 핵심 기능과 HTTP API설계 방법을 학습한다.

  • 목차
    • HTTP 정의
    • HTTP의 비연결성 (Connectionless)
    • HTTP(Protocol) 오버헤드
    • HTTP의 무상태성 (Stateless)
    • HTTP 통신의 구성 요소
    • HTTP 상태 코드
    • HTTP 메서드 종류와 특징
    • HTTP 캐싱
    • HTTP 쿠키
    • CORS(Cross-Origin Resource Sharing)

HTTP 정의

HTTP(Hypertext Transfer Protocol)란?

  • 인터넷에서 데이터를 주고 받을 수 있는 텍스트 기반의 통신 규칙 또는 프로토콜. -> 인터넷 통신규칙

HTTP 동작방식

  • “요청” 과 “응답” 메세지로 대응되는 구조로서 클라이언트는 특정 형식의 요청 메서드, URI 와 request modifiers, 클라이언트 정보, body contents를 포함한 MIME 타입의 프로토콜 버전을 서버로 전송한다. 서버는 프로토콜 버전, 상태 코드, 상태 메세지, 서버정보, 구성 메타정보와 응답 본문을 포함하여 응답한다.

 

HTTP의 비연결성 (Connectionless)

  • 클라이언트와 서버가 한 번 연결을 맺은 후, 클라이언트 요청에 대한 응답을 마치면 연결을 끊어 버리는 특성. HTTP는 불특정 다수의 통신 기반으로 설계되어 있으므로 연결 유지를 위한 리소스를 줄여 더 많은 유저의 요청을 처리할 수 있다는 장점을 가지게 됨.

 

HTTP(Protocol) 오버헤드

  • 네트워크를 통해 대상으로 라우팅되는 데이터와 함께 전송되어야하는 정보를 말하며, 올바른 대상에 도달하기 위해 전송중인 데이터에 추가로 보내지는 정보.
  • 통상 패킷/프레임 등의 선두에 있는 헤더(Header) 상에 위치하므로 Header 라고도 함.
  • 전송 기능 자체는 내가 보내고자 하는 대상에게 제대로 도착했는지를 확인하지 않는다. “보내다” 라는 행위의 본질은 아니지만 원하는 대상을 정확히 찾아내어라는 간접적인 처리를 프로토콜 오버헤드를 통해 하는 것.
  • 전송중인 데이터와 관련없는 정보들이 담겨 있지만 출발지 및 도착지 주소와 같이 주 기능을 보완해 줄 수 있는 정보들이 담겨있음. -> 정보 전송의 신뢰성 상승 및 안정적 시스템 운용 가능.
  • 오버헤드에 관한 정보통신기술용어해설에 기술된 정의
    • 목적
    • 정보 전송의 신뢰성 확보 및 시스템의 안정적 운용 등을 위함
    • 성격
    • 실제 운반되는 정보(페이로드)에 추가되는 성격의 운용 및 유지보수를 위한 신호
    • 담겨진 정보
    • 각 전송 구간별 페이로드의 종류,형태, 출발지 및 도착지 주소, 운용 유지보수 정보 등
    • 위치
    • 통상, 오버헤드는 패킷/프레임 등의 선두에 있는 헤더(Header) 상에 위치함

 

HTTP의 무상태성 (Stateless)

  • Connectionless로 인해 클라이언트를 식별할 수 없는 상태. -> 요청에 대한 응답을 처리한 후 연결을 끊어버린 서버가 클라이언트의 이전 상태를 알 수 없는 현상을 말함.
    • cookie, session, token 으로 상태를 기억하여 단점을 보완함.

 

HTTP 통신의 구성 요소

  • 클라이언트 (user Agent) : 사용자를 대신해 요청을 보내는 일을 수행
  • 서버 (server) : 클라이언트가 요청하게 되는 대상으로, 개발자가 특정 기능을 수행하도록 설계해 놓은 코드를 실행하여 클라이언트에게 정보를 제공함.
  • 프록시 (proxy) : 서버와 클라이언트 사이의 중계 역할을 함. 동일 프로토콜로 연결하며 캐싱, 필터링, 로드 밸런싱, 인증, 로깅 역할 수행
  • 참고. 중계역할을 하는 요소들
    • 게이트웨이 (gateway) : 프록시 처럼 중계 역할을 하나, HTTP 프로토콜 이외 기능 수행 (프로토콜 변환 등)
    • 릴레이 (relay) : 단순 프록시 (단순 중계)역할만 함

 

HTTP 상태 코드

클라이언트가 서버에 요청을 하면, 서버는 요청에 대한 처리 상태를 숫자로 반환하는 것

  • 상태코드의 분류
    • 1XX: Informational(정보 제공) 요청이 수신되어 처리중이라는 의미.
    • 2XX: Success(요청 성공) 클라이언트의 요청이 서버에서 성공적으로 처리되었다는 의미.
    • 3XX: Redirection(리다이렉션) 완전한 처리를 위해서 추가 동작이 필요한 경우로 주로 서버의 주소 또는 요청한 URI의 웹 문서가 이동되었으니 그 주소로 다시 시도하라는 의미.
    • 4XX: Client Error(클라이언트 에러) 없는 페이지를 요청하는 등 클라이언트의 요청 메시지 내용이 잘못된 경우를 의미.
    • 5XX: Server Error(서버 에러) 서버 사정으로 메시지 처리에 문제가 발생한 경우입니다. 서버의 부하, DB 처리 과정 오류, 서버에서 익셉션이 발생하는 경우를 의미.
  • 주요 상태코드
    • 200 : 서버가 요청을 제대로 처리함
    • 400 : 잘못된 요청 (주로 헤더 포멧이 HTTP 규약에 맞지 않을 경우)
    • 401 : 권한 없음 (지정한 리소스에 대한 접근권한 없음)
    • 403 : 금지됨 (지정한 리소스에 대한 접근 금지. 서버가 요청을 거부하고 있다는 의미)
    • 404 : 찾을 수 없음 (요청한 자원이 서버에 존재하지 않음)
    • 500 : 내부 서버 오류 (서버에 에러가 발생한 것을 의미)
    • 503 : 서비스 불가능 (주로 Proxy 장비에서 서버에 서비스가 불가능할 때 사용됨)

 

HTTP 메서드 종류와 특징

GET - Cacheable

  • 조회를 목적으로 사용하는 메서드. 데이터를 읽거나(Read) 검색(Retrieve)할 때 사용함.

POST

  • 서버로 데이터를 전송할 때 사용하는 메서드. 본문 유형은 Content-Type 헤더로 나타냄.
  • POST 요청은 보통 HTML form을 통해 서버에 전송하며, 서버에 변경사항을 만듬(멱등성이 없음).
  • 신선도 정보 포함시에만 캐싱

PUT

  • 데이터 갱신, 작성시 사용하며 주로 수정 시 사용하는 메서드.(모든 자원이 변경되므로 주의)
  • PUT은 한 번을 보내도, 여러 번을 연속으로 보내도 같은 효과를 보임(멱등성이 있음).

DELETE

  • 지정한 리소스의 삭제를 목적으로 함.

HEAD - Cacheable

  • 서버 리소스의 헤더(메타 데이터)의 취득이 목적으로 특정 리소스를 GET 메서드로 요청했을 때 돌아올 헤더를 요청함.

OPTIONS

  • URL 또는 서버에 대해 허용된 통신 메서드를 요청함. 클라이언트는 이 방법으로 URL을 지정하거나 “*” 을 지정하여 전체 서버 참조 가능.
  • CORS 사전 요청시 OPTIONS 로 요청함.

PATCH

  • 리소스의 일부분을 수정시 사용함.
  • PUT 과는 달리 일부의 자원만 수정 가능.

CONNECT

  • 요청한 리소스에 대해 양방향 연결을 시작하는 메소드로 터널을 열기 위해서 사용될 수 있음.
  • SSL을 사용하는 웹사이트에 접속하는데 사용될 수 있음. 1) 클라이언트는 원하는 목적지와의 TCP 연결을 HTTP 프록시 서버에 요청 2) 서버는 클라이언트를 대신하여 연결 생성 3) 한번 서버에 의해 연결이 수립되면, 프록시 서버는 클라이언트에 오고가는 TCP 스트림을 계속 프록시 함.

TRACE

  • 클라이언트와 목적지 서버 사이에 있는 모든 HTTP 애플리케이션의 요청/응답 연쇄를 따라가면서 자신이 보낸 메시지의 이상 유무 파악 가능함.

 

HTTP 캐싱

  • 한 번 가져온 데이터를 가까운 곳에 저장해 두고 다음번에 다시 먼 곳에서 그것을 가져올 필요 없이 저장해둔 것을 사용하는 일종의 성능 향상 기법
  • HTTP 응답을 저장해 두고 다음번에 동일한 HTTP 요청이 시도되면 저장해 둔 HTTP 응답을 재활용.
  • HTTP 응답을 저장해 두는 저장소
    • 사설 캐시(Private Cache). 지역 캐시(Local Cache)라고도 부름.
      • 한 사용자에 의해서만 재활용될 수 있는 것들이 저장되는 저장소. 최초의 HTTP 요청은 서버에게 전송되어 HTTP 응답을 받아오게 되고, 이를 사설 캐시에 저장해 두면 다음번에 동일한 HTTP 요청이 시도될 때는 서버에 해당 HTTP 요청을 다시 보내지 않고 저장되어 있는 HTTP 응답을 재활용하게 된다. 대표적인 사설 캐시로는 브라우저 캐시가 있다. 브라우저 캐시는 기본적으로 사용자가 HTTP 요청을 통해 다운로드한 모든 문서들을 저장하고 있다. 이렇게 저장된 문서들은 뒤로 가기 혹은 앞으로 가기를 할 때, 문서 저장을 할 때, 페이지 소스 보기를 할 때 등의 경우에 재활용이 된다.
    • 공유 캐시(Shared Cache).
      • 여러 사용자들에 의해 재활용될 수 있는 것들이 저장되는 저장소. 최초의 HTTP 요청은 공유 캐시를 거쳐 서버에게 전송되어 HTTP 응답을 받아오게 되고, 이를 공유 캐시에 저장해 두면 다음번에 동일한 HTTP 요청이 공유 캐시에게 전달될 때 서버에 해당 HTTP 요청을 다시 보내지 않고 저장되어 있는 HTTP 응답을 클라이언트에게 반환하게 된다. 대표적인 공유 캐시로는 프록시 캐시가 있다. ISP 혹은 회사 측에서 로컬 네트워크 인프라의 일부로서 구축해둔 웹 프록시가 이러한 역할을 담당할 수 있다. 그러면 자주 사용되는 데이터들의 경우에 네트워크 트래픽을 최소화하여 많은 구성원들이 해당 데이터를 효율적으로 사용할 수 있게 되는 것이다.

 

HTTP 쿠키

HTTP 쿠키란?

  • 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각. 브라우저는 그 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재 요청 시 저장된 데이터를 함께 전송.
  • 쿠키는 stateless 한 HTTP 통신에서 클라이언트에게 정보(표시)를 주어 해당 클라이언트를 식별하기 위한 목적으로 만들어짐.

HTTP 쿠키 특징

  • 쿠키는 한개에 4KB 까지 저장 가능하며, 최대 300개 까지 저장할 수 있다.
  • 쿠키는 클라이언트에 저장된다.
  • 쿠키에는 이름, 값, 만료날짜, 경로 정보가 들어있다.
  • 기본적으로 쿠키는 웹 브라우저가 종료되면 삭제된다. (만료날짜를 지정해 주면 만료일이 되야 삭제된다.)
  • 웹 브라우저에 해당 서버의 쿠키 정보가 있으면 HTTP 요청 (HTTP 헤더의 Cookie)에 무조건 담아 보낸다.

HTTP 쿠키 동작방식

요청을 받은 서버에서 쿠키를 클라이언트(웹 브라우저)로 보내고 클라이언트는 쿠키를 받으면 도메인 서버 이름으로 정렬된 쿠키 디렉토리에 쿠키(정보)를 저장한다.
이후 클라이언트가 동일한 서버로 HTTP 요청을 보내면 저장된 쿠키도 같이 전송되며, 만약 서버에서 쿠키에 업데이트된 내용이 있으면 응답할 때 다시 업데이트된 쿠키를 보내준다.

HTTP 쿠키 보안

  • Secure
    쿠키는 기본적으로 http, https를 구분하지 않고 전송함.
    Secure 옵션을 적용하면 https인 경우에만 쿠키를 전송하게 됨.
  • HttpOnly 해당 옵션 적용 시 자바스크립트에서 document.cookie 접근이 불가능 하게 되며, HTTP 전송에만 사용 가능하게 됨.
  • SameSite
    • Strict : 동일한 도메인에서만 쿠키 전송 허용
    • Lax : 기본적으로는 Strict과 동일하지만 safe한 요청(http get 방식, anker tag, 를 통한 접근은 허용
    • None : 모든 전송 허용. 보안에 취약하므로 주로 https 프로토콜에 secure 속성과 함께 사용.

 

CORS(Cross-Origin Resource Sharing)

CORS 란?

  • 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 말 그대로 다른 출처의 리소스 공유에 대한 허용 / 비허용 정책을 말함.
  • 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행함.
  • <img>, <video>, <script>, <link> tag 등은 기본적으로 Cross-Origin 정책을 지원함.
  • XMLHttpRequest나 Fatch API는 same-origin 정책을 따르므로 Cross-Origin 불가 (보안상의 이유로 브라우저에서는 내부에서 작성된 cross-origin HTTP를 제한하고 있음.)

브라우저의 CORS 동작방식

  1. 클라이언트에서 HTTP request header에 Origin을 담아 전달
  2. 서버는 응답헤더에 Access-Control-Allow-Origin 을 담아 클라이언트로 전달
  3. 클라이언트에서 Origin과 서버가 보내준 Access-Control-Allow-Origin을 비교 후 유효하지 않다면 CORS 에러 발생

CORS 작동 방식 3가지

  1. 예비 요청 (Preflight Request): 본 요청을 보내기 전에 브라우저 스스로 안전한 요청인지 확인하기 위해 OPTIONS 메서드를 이용하여 예비 요청을 보내는 것. - 예비 요청에 대한 응답으로 서버로부터 허용, 금지에 대한 헤더 정보를 받게 됨. 브라우저는 해당 요청이 안전한지 확인 한 후 본 요청을 보냄.
  2. 단순 요청 (Simple Request) : 예비 요청(Prefilght)을 생략하고 바로 서버에 본 요청을 보낸 후, 서버가 Access-Control-Allow-Origin 헤더를 응답해주면 브라우저가 CORS정책 위반 여부를 검사하는 방식.
    - 3가지 경우를 만족할 때만 가능
    1) 요청의 메소드는 GET, HEAD, POST 중 하나여야 함.
    2) 요청이 Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width 헤더일 경우 에만 가능.
    3) Content-Type 헤더가 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나여야 함.
  3. 인증된 요청 (Credentialed Request) : 클라이언트에서 서버로 요청을 보낼 때 자격 인증 정보(Credential)를 함께 전달하는 것.
    • 자격 인증 정보란 세션 ID가 저장되어있는 쿠키(Cookie) 혹은 Authorization 헤더에 설정하는 토큰 값 등
	/* 
	 * 클라이언트 설정 
	 * request 요청 script에서 credentials 옵션을 설정해 준다. 
	 */
	// credentials 설정 옵션 값 
	same-origin (기본값) : 같은 출처 간 요청에만 인증 정보 전송 가능
	include	: 모든 요청에 인증 정보 전송 가능
	omit : 모든 요청에 인증 정보 전송 불가

	// 서버 설정   
	Access-Control-Allow-Credentials : true
	Access-Control-Allow-Origin : "*" 불가
	Access-Control-Allow-Methods : "*" 불가
	Access-Control-Allow-Headers : "*" 불가

 

CORS 해결책

  • 서버 문법에 맞게 Access-Control-Allow-Origin 헤더값에 허용할 출처 설정
  • 프록시 서버 직접 구축
  • 서버에서 직접 통신 구현
반응형
반응형

JAVA 1.0a2 - 1995년

  • 최초 버전
  • Oak 라는 이름으로 불림

 

JAVA 1.0 - 1996년

  • 안정화 작업을 거친 1.0.2 버전에서 Java로 이름 변경.

 

JAVA 1.2 (Playground) - 1998년

  • 해당 버젼부터 코드명 등장
  • 플렛폼을 J2SE, J2EE, J2ME로 구성

 

JAVA 1.3 (Kestrel) - 2000년

  • Java XML API, JNDI 등이 추가됨

 

JAVA 1.4 (Merlin) - 2002년

  • IPv6 지원
  • 정규표현식 지원
  • 논블로킹 IO : IO를 비차단으로 최적화하여 실행 중인 애플리케이션 속도 향상.
  • 이미지처리 API : 컴포넌트 개발자가 JAVA코드로 이미지를 조작할 수 있음.
  • JAVA 커피잔 로고는 2003년 (릴리즈 버젼 1.4 와 5.0 사이에) 자바 컨퍼런스에서 처음 사용함.

 

JAVA 5 (Tiger) - 2004년

  • 처음에는 1.5로 명명되었으나 성숙도, 안정성, 확장성 및 보안이 크게 향상된 새로운 기능이 포함된 주요 릴리스였기 때문에 5.0으로 공개함. (이때부터 앞의 1.이 없어짐.)
  • Generics : 외부에서 형태를 정해주는 제너릭. ClassCastException을 컴파일시 검증 가능.
  • 메타데이터라고도 하는 어노테이션은 메타데이터 인식 유틸리티가 클래스와 메서드를 처리할 수 있도록 태그를 지정하는 데 사용(즉, 구성 요소를 다른 구성 요소가 인식하고 특정 작업을 수행하는 것으로 레이블이 지정됨).
  • Auto Boxing/Unboxing : 오토 박싱/언박싱 기능을 통해 원시타입 객체를 래퍼 클래스로 자동 변환 해줌.
  • Enumeration : 열거형(enum) 기능 추가됨
  • 변수는 한 유형의 임의 개수의 매개 변수를 지원하는 메서드에 대한 약어 제공. 메서드의 마지막 매개 변수는 형식 이름과 세 개의 점(예: String…)을 사용하여 선언되며 이는 해당 형식의 임의의 수의 인수를 제공하고 배열에 배치할 수 있음을 의미.
  • for each문 기능 향상 : 컬렉션 및 배열에서도 사용 가능.
  • 멀티쓰레드 상의 시멘틱스 향상
  • Static imports
  • RMI(Remote Method Invocation, 원격 메소드 호출), Swing, 동시성 유틸리티(Processes and Threads) 및 Scanner 클래스 개선
  • Java 5는 Apple Mac OS X 10.4에서 처음 사용할 수 있으며 Apple Mac OS X 10.5에 설치된 기본 버전.

 

JAVA 6 (Mustang) - 2006년

  • 가비지 컬렉터 G1(Garbage First) 테스트용으로 추가.
  • 2010년 1월 오라클이 Sun Microsystems를 인수하게 됨에 따라 Sun Microsystems에서 출시한 마지막 주요 릴리스 버전.
  • 핵심 플랫폼의 성능 향상(애플리케이션 실행 속도 향상. 실행에 필요한 메모리 또는 CPU 감소).
  • 향상된 웹 서비스 지원(웹 응용프로그램 개발에 필요한 최적화된 구성요소).
  • JDBC 4.0(데이터베이스를 사용한 애플리케이션 개발에 필요한 최적화된 구성 요소).
  • Java 컴파일러 API(코드에서 코드를 컴파일하는 데 사용되는 구성 요소를 호출할 수 있습니다.)
  • API에서의 SwingWorker 통합, 테이블 정렬 및 필터링, Swing 이중 버퍼링(회색 영역 효과 제거)과 같은 전반적으로 데스크톱 애플리케이션을 위한 인터페이스를 만드는 데 사용되는 구성 요소의 개선.
  • 2008년 12월 JavaFX 1.0 SDK 출시. JavaFX는 모든 플랫폼의 그래픽 사용자 인터페이스를 만드는 데 적합. 초기 버전은 스크립트 언어. 2008년까지 자바에서는 사용자 인터페이스를 만드는 두 가지 방법 존재했음(AWT, Swing)

 

JAVA 7 (Dolphin) - 2011년

  • 동적 바이트 코드(기본적으로 Java 코드는 Python, Ruby, Perl, Javascript 및 Groovy와 같은 비 자바 언어로 구현된 코드를 사용할 수 있음)를 사용하여 dynamic languages를 JVM에서 지원.
  • 압축된 64비트 포인터(JVM의 내부 최적화로 메모리 사용량 감소)
  • 프로젝트 “Coin” 하에 그룹화된 작은 변경 사항들:
    • Switch-case 문에서 문자열 사용 가능
    • Try-catch 문에서 자동 리소스 관리
    • 제네릭의 개선된 유형 추론
    • 이진 정수 리터럴: 정수 숫자는 0b(또는 0B) 형식과 하나 이상의 이진 숫자(0 또는 1)를 사용하여 이진 숫자로 직접 나타낼 수 있음
    • 다중 예외처리 개선
  • 동시성 향상
  • 새 I/O 라이브러리(파일에서 데이터 읽기/쓰기에 추가된 새 클래스)
  • Timsort 알고리즘은 성능이 더 좋기 때문에 병합 정렬 대신 객체의 컬렉션과 배열을 정렬하기 위해 도입됨. (Merge Sort(병합 정렬) + Insertion Sort(삽입 정렬))

Java 7을 시작으로 Java SE Platform Edition의 오픈 소스 레퍼런스 구현체인 OpenJDK가 탄생.

 

JAVA 8 (Spider) - 2014년

  • LTS버젼. 2030년 12월까지.
  • 오라클 인수 후 첫 번째 버전
  • 람다 표현식 지원(함수형 프로그래밍 특징)
  • 인터페이스에서 default 메서드 지원 (인터페이스에 함수 구현 내용까지 포함 가능)
  • 새로운 날짜 및 시간 API
  • 스트림을 사용하여 병렬 처리를 수행하는 새로운 방법 추가
  • JavaScript(Nashorn 프로젝트)와의 통합 개선됨.
  • GC 프로세스 개선
  • Permanent Generation이 Metaspace로 대체됨
    • Permanent Generation
      • Permanent Generation은 Class 혹은 Method Code가 저장되는 영역
      • PermGen은 Heap 영역에 속함
      • Default로 제한된 크기를 가지고 있음
    • Metaspace
      • Metaspace는 Java 클래스 로더가 현재까지 로드한 Class들의 메타데이터가 저장되는 공간
      • JVM에 의해 관리되는 Heap 영역이 아니라 OS 레벨에서 관리되는 Native 메모리 영역에 위치
      • Default로 제한된 크기를 가지고 있지 않고, 필요한 만큼 늘어남

Java 8부터는 상표법상의 문제를 피하기 위해 코드네임 삭제됨. 대신 메이저, 마이너 및 보안 업데이트 릴리스를 쉽게 구분하는 시맨틱 버전이 채택됨.

$Major.$minor.$SECURITY

터미널에서 Java 버전을 실행할 때(Java 8이 설치된 경우) 아래와 유사한 로그가 표시됩니다.

	$ java -version
	java version "1.8.0_162"
	JavaTM SE Runtime Environment build 1.8.0_162-b12
	Java HotSpotTM 64-Bit Server VM build 25.162-b12, mixed mode

로그 버전 번호의 의미 :

  • 1은 Java SE Platform Specification의 새 버전에 지정된 대로 중요한 새 기능이 포함된 주요 릴리스에 대해 증분된 주 버전 번호를 나타냅니다.
  • 8은 부 버전 번호를 나타내며, 호환되는 버그 수정, 표준 API에 대한 개정 및 기타 작은 기능을 포함할 수 있는 부 업데이트 릴리스에 대해 증가합니다.
  • 0은 보안 향상에 필요한 수정 사항을 포함하여 중요한 수정 사항이 포함된 보안 업데이트 릴리스에 대해 증가된 보안 수준을 나타냅니다. $MINOR가 증가하면 $SECURITY가 0으로 재설정되지 않으므로 사용자는 이 버전이 더 안전하다는 것을 알 수 있습니다.
  • 162는 빌드 번호입니다.
  • b12는 추가 빌드 정보를 나타냅니다.

이 버전 관리 스타일은 Java 애플리케이션에 매우 일반적이기 때문에 일반적인 업계 관행에 맞추기 위해 이 버전 관리 스타일을 채택했습니다.

 

JAVA 9 - 2017년

  • 직소 프로젝트 시작
    • 런타임이 모듈화된 것이 가장 큰 특징. 서로 다른 패키지간의 캡슐화가 가능해짐. jigsaw는 모듈을 만들고 모듈에 명시적으로 외부에서 호출할 수 있는 API를 선언함. 언어 레벨에서 API 작성자가 외부에 노출한 API 외에는 접근불가. 모듈은 그 모듈에서 사용할 다른 모듈을 선언. JDK는 이 기능을 통해 모든 내부 API를 캡슐화하여 구성.
	// Java 코드 최상위에 module-info.java 파일을 만들고, 아래와 같이 사용함
	module java.sql {
		requires public java.logging;
		requires public java.xml;
		exports java.sql;
		exports javax.sql;
		exports javax.transaction.xa;
	}
  • Java를 쉘 처럼 사용할 수 있는 JShell 추가
  • interface에서 private method 지원
  • 향상된 try-with-resources : final 변수도 리소스로 사용가능
  • “_” 이 올바른 식별자명에서 제거됨
  • G1(Garbage-First) 가비지 수집기에 대한 향상된 기능. 이 기능이 기본 가비지 콜렉터가 됨
  • 내부적으로 더 작은 규모의 String 표현 사용
  • 동시성 업데이트(병렬 실행 관련)
  • collections 을 위한 Factory methods
	// 기존 collection
	List<String> temp = new ArrayList<>();
	cars.add("A1");
	cars.add("B1");
	cars.add("C1");
	...

  	// collection factory
	List<String> temp = Arrays.asList("A1", "B1", "C1");
  • 이미지를 처리하는 코드를 작성하는 데 사용되는 구성 요소의 이미지 처리 API 최적화 업데이트
  • 프로퍼티 파일에 UTF-8 지원
  • 이 버젼부터 64비트만 출시. 32비트는 나오지 않음

 

JAVA 10 - 2018년 3월

  • Oracle은 Java 릴리스 스타일을 변경하여 6개월마다 새 버전이 릴리스 됨.
  • Local-Variable Type Interface (로컬변수 타입추론)
    • 로컬 변수 타입을 var 로 선언 가능.
    • 제약사항 :
      • 로컬변수만 가능
      • 초기화 필수. null 불가.
	var list = new ArrayList<String>();	//ArrayList<String> 으로 추론
	
	var numbers = List.of(1, 2, 3, 4, 5);	//List<Integer> 으로 추론

	for (var number : numbers){		//Integer 추론
		System.out.println(number);
	}
  • GC 성능 향상
  • Appliction CDS(class data sharing) 기능 추가
    • 애플리케이션 로딩의 시작 시간 향상을 위한 JVM의 주요 기능. 서로 다른 JVM 간에 클래스 메타데이터를 공유할 수 있으므로 시작 시간과 메모리 사용량이 줄어듬.
  • 추가 동시성 업데이트(병렬 실행 관련)
  • 대체 메모리 장치에 힙 메모리 할당(JVM이 Java 프로그램을 실행하는 데 필요한 메모리(힙 메모리)를 대체 메모리 장치에 할당할 수 있으므로 힙을 휘발성 RAM과 비휘발성 RAM 간에 분할도 가능)
  • Thread-Local Handshakes VM safepoint(모든 쓰레드를 일시정지 시키는 작업)를 수행할 필요 없이 개별 스레드를 stop 시키고 콜백을 수행하도록 할 수 있는 기능.

 

JAVA 11 - 2018년 9월

  • LTS 버젼. JAVA 11 : 2026년 9월까지 지원
  • enterprise Java applications 및 Corba(원격 호출을 위한 매우 오래된 기술로 응용프로그램이 다른 컴퓨터에 설치된 응용프로그램과 통신할 수 있음) 모듈을 구축하는 데 사용되는 JEE 고급 구성요소 제거.
  • 람다 매개 변수에 대한 로컬 변수 구문을 사용하면 암묵적으로 입력된 람다 식의 형식 매개 변수를 선언할 때 var 키워드를 사용 가능
     (var x, var y) -> x.process(y) => (x, y) -> x.process(y)
    
  • 오버헤드가 낮은 가비지 컬렉터인 Epsilon(GC가 없으므로 기본적으로 GC 없이도 애플리케이션을 실행할 수 있음)은 기본적으로 가비지 수집에 더 많은 최적화를 제공
  • 병렬 실행과 관련된 더 많은 동시성 업데이트.
  • Nashorn JavaScript 스크립트 엔진 및 API는 향후 릴리스에서 제거하기 위해 더 이상 사용되지 않는 것으로 표시. ( ECMAScript 구조가 상당히 빠르게 진화하여 유지의 어려움 때문 )
  • Oracle JDK와 OpenJDK가 통합되었으며 Oracle JDK 가 유료 모델로 전환
  • 새로운 String 메서드 추가
     strip() : 문자열 앞, 뒤의 공백 제거
     stripLeading() : 문자열 앞의 공백 제거
     stripTrailing() : 문자열 뒤의 공백 제거
     isBlank() : 문자열이 비어있거나 공백만 포함되어있을 경우 true를 반환. 즉, String.trim().isEmpty() 호출과 같음
     lines() : 문자열을 라인 단위로 쪼개는 스트림을 반환
     repeat(n) : 지정된 수 만큼 문자열을 반복하여 붙여 반환
    

 

JAVA 12 - 2019년 3월

  • GC 일시 중지 시간을 단축하는 Shenandah라는 새로운 실험적 Garbage Collector(GC) 알고리즘.
  • switch 문 수정됨. 브레이크 문 필요없음.
     switch (day) {
         case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
         case TUESDAY                -> System.out.println(7);
         case THURSDAY, SATURDAY     -> System.out.println(8);
         case WEDNESDAY              -> System.out.println(9);
     }
    
  • 주요 클래스 파일 및 런타임 아티팩트의 공칭 설명을 모델링하는 JVM 상수 API. 이 API는 클래스와 메서드를 조작하는데 유용.
  • G1 가비지 컬렉터 성능 개선
  • JDK 빌드 프로세스를 개선하기 위한 CDS(class data sharing) 아카이브를 기본값으로 설정함.
  • 약 100개의 마이크로벤치마크16이 JDK 소스에 추가

 

JAVA 13 - 2019년 9월

  • 동적 CDS 아카이브(JDK 12에 추가된 CDS 아카이브의 지원 향상)
    • 12에서는 클래스 목록을 만든 다음 해당 클래스 목록을 아카이브에 덤프하는 단계가 필요했음. 13에서는 동적 저장기능이 있어 어플리케이션 종료시에 공유 아카이브 생성 가능.
  • 가비지 컬렉터 기능 향상
  • 레거시 소켓 API의 새로운 구현
  • 유니코드 12.1 지원
  • 텍스트 블록 지원
     // 줄바꿈 문자 자동 지원
     String str = """
        This
        is
        text block
     """;
    
  • switch 문에 yield 예약어 추가
      var a = switch (day) {
         case MONDAY, FRIDAY, SUNDAY:
             yield 6;
         case TUESDAY:
             yield 7;
         case THURSDAY, SATURDAY:
             yield 8;
         case WEDNESDAY:
             yield 9;
     };
    

 

JAVA 14 - 2020년 3월

연산자 인스턴스에 대한 패턴 일치

  • Java 애플리케이션 및 JVM이 실행중일 때 프로파일링 및 진단 데이터를 수집하는 JFR Event Streaming API
  • G1 가비지 컬렉터의 추가 향상된 기능
  • CMS(Concurrent Mark Sweep) 가비지 컬렉터 제거
  • macOS용 Z 가비지 컬렉터 지원
  • 상용구 클래스를 선언을 줄여주는 record 도입.
     // 기존 상용구 클래스
     final class Point {
         public final int x;
         public final int y;
    
         public Point(int x, int y) {
             this.x = x;
             this.y = y;
         }
     }
     ...
    	
     // 레코드 사용
     record Point(int x, int y) { }
    
  • Java 힙 외부의 메모리에 안전하고 효율적으로 접근할 수 있도록 지원하는 외부 메모리 액세스 API
  • NullPointerExceptions 향상 : 정확히 어떤 변수가 null인지 기술해 줌.

 

JAVA 15 / 2020년 9월

  • Nashorn JavaScript 엔진 제거
  • sealed and hidden classes 추가
	/* 
	 * Game.java 파일
	 * permits 로 선언된 Nintendo, Sony class 만 Game class 를 상속할 수 있다.
	 */
	public sealed class Game permits Nintendo, Sony {}
	...
	
	/* 
	 * Nintendo.java 파일
	 * final 로 선언된 Nintendo Class. 다른 클래스에서 Nintendo 클래스를 상속할 수 없다.
	 */
	public final class Nintendo extends Game {} 	// Game Class 상속가능
	...


	/* 
	 * Sony.java 파일
	 * non-sealed 선언되었기 때문에 Sony class는 아무 클래스에서나 상속 가능하다.
	 */
	public non-sealed class Sony extends Game {}	// Game Class 상속가능
	...

	/* 
	 * Playstation.java 파일
	 * Nintendo 가 final 로 선언된 class 이기 때문에 상속할 수 없다.
	 */
	public class Playstation extends Nintendo {} // Nintendo Class 상속불가
	
	
	/* 
	 * Vita.java 파일
	 * non-sealed class 인 Sony.java 상속이 가능하다
	 */
	public class Vita extends Sony {} // 상속가능
	...
	
  • Edwards-Curve Digital Signature Algorithm(EdDSA) : 암호화 서명 지원
  • Legacy DatagramSocket API 성능 향상
  • Biased Locking이 비활성화 됨 : 멀티스레드 애플리케이션의 성능이 향상됨

 

JAVA 16 - 2021년 3월

  • Vector API 도입 : 대용량 데이터를 효과적으로 다루는 클래스. 용량 변경이 용이하며 어떤 종류의 객체도 담을 수 있음
  • JDK 내부의 강력한 캡슐화
  • Foreign Linker API 도입 : 다른 프로그래밍 언어로 작성된 라이브러리 및 외부 메모리에 액세스하기 위해서 사용되던 JNI(Java Native Interface)의 대체제
  • 사용하지 않는 HotSpot 클래스 메타데이터(즉, 메타스페이스) 메모리를 운영 체제로 보다 신속하게 반환할 수 있는 Elastic 메타스페이스의 도입

 

JAVA 17 - 2021년 9월

  • LTS버젼 : 2029년 9월까지 지원
  • JDK 16에 도입된 Vector API의 성능 및 구현 향상
  • sealed class 및 interface 개선
  • switch 문에 패턴 매칭 기능, Gaurded Patterns, Null Cases 추가
     return switch (obj) {
         case Integer i -> "It is an integer";
         case String s -> "It is a string";
         case Employee employee && employee.getDept().equals("IT") -> "IT Employee";
         case null -> "It is a null object";
         default -> "It is none of the known data types";
     };
    
  • macOS별 향상된 기능
  • 의사 난수 생성기를 위한 향상된 기능: 예측이 어려운 난수 생성 API 정식 추가
  • JDK 내부 캡슐화 기능 향상
  • Apple API 사용 안 함(JDK 18에서 제거 준비)
  • Security Manager 사용 안 함(JDK 18에서 제거 준비)
  • Foreign Function & Memory API는 개발자들이 JNI의 위험 없이 네이티브 라이브러리를 호출하고 네이티브 데이터를 처리할 수 있도록 하기 위해 이전에 인큐베이팅했던 두 개의 API인 Foreign-Memory Access API와 Foreign Linker API를 병합.

JDK 17의 기능 목록은 성능을 향상시키고 오래된 API를 사용/폐기하기 위해 JVM 내부에 초점을 맞추고 있음.

반응형
반응형

개요

JAVA 8 에서 17 로 넘어가려는 움직임이 보인다. 간략하게나마 이유를 알아보고 진짜 넘어갈 필요가 있는지 한번 생각해 보자.
자세한 내용이 궁금하면 다른 사람의 글을 참고하자.

  • 목차
    • 아직도 JAVA 8을 사용하는 이유?
    • java 9 ~ 17 까지의 변경점들

 

아직도 JAVA 8을 사용하는 이유?


  • 호환성
    JAVA8이 나왔을 당시만 해도 JAVA 1.6, 1.7에서 자연스럽게 8(공식적으로 JAVA 1.8 버전부터 JAVA8로 표기하기로 함)로 업그레이드 했다. 이전 버젼들과 호환성이 좋았고 업그레이드에 큰 문제가 거의 없어서 자연스럽게 1.8을 선택했던 것 같다.
  • LTS
    JAVA8 은 LTS(Long Term Support) 버전이다. 말 그대로 Oracle사에서 오랜기간 지원해주는 버젼이라는 뜻이다. JAVA17 이 나오기 전까지 LTS버젼은 JAVA11 이 있었지만, 8보다도 지원 기간이 짧았기 때문에 시스템 운영면에서 굳이 11로 넘어가는 모험을 할 필요가 없었을 것이다. 그래서 아직까지도 8 버젼을 쓰는 곳이 많을 수 밖에 없다.
  • LTS 버젼별 지원 기간
  •   JAVA 8 : 2030년 12월
      JAVA 11 : 2026년 9월
      JAVA 17 : 2029년 9월
    

그렇다면 17도 8보다 지원기간이 짧은데 왜 넘어가야 할까?

 

JAVA 9~17 까지의 변경점들


JAVA17은 이전 버젼들의 변화들을 포함하고 있다.
내가 주목하는 점은 개발시의 이점이 있을만한 편의성 개선에 있다.
어떤 것들이 쓸모가 있을지 알아보자.

개발시 사용될 변경점들

  • Stream Class - iterate (JAVA 9)
    • 1.6 때 JAVA를 공부해서 그런가 개인적으로는 iterate 같은 함수 형태의 반복문을 비 선호하는 편이다. 물론 필요에 따라 사용하긴 했다.
      JAVA 9 에서는 iterate() 를 Override 하여 파라미터 3가지를 받는 형태의 메서드가 추가되었다.
      기존 for문 처럼 초기값, 반복될 범위, 증가값을 파라미터로 전달 할 수 있게 되었다. 그것도 반복 범위와 증가값을 람다 형태로 말이다.아니 이럴거면 기존 for문을 쓰라고 경우에 따라 JAVA 9 버젼의 iterate()를 쓸 일이 있을 것 같다.
  • interface private method (JAVA 9)
    • JAVA 8의 interface default Method에 이어 interface private Method 가 추가되었다. 인터페이스 상에서 정의해 둔 것을 상속한 클래스에서 구현할 수 없도록 하여 변경할 수 없도록 강제하는 것이 가능해졌다.
  • var (JAVA10) 타입추론 개념으로 var라는 형태를 사용할 수 있다.
    var는 몇가지 제약사항이 있다.
    • 지역변수로만 사용가능
    • 초기화 필수, null 불가
      • 타입 추론을 위해서는 초기화가 필수겠지? 그러니 null도 사용할 수 없다.

        C#을 안해봐서 그런지 JAVA에 꼭 필요한가 의문이 든다. 람다식이 나온 후로 적응하기 힘들어하는 내가 문제겠지..
        뭔가 편리할 것 같긴 한데 큰 변화라고 하긴 힘들어보인다. 오히려 사용하기 위해 공부를 해야하는 느낌이지만 일단 알아두고 나중에 써먹자.
  • switch~case문의 변화 (Java 12 ~ 17)
    기존에는 ‘case’마다 하나의 값만 지정이 가능했기 때문에 ‘break’문을 적절히 사용하면서 로직을 구성해야 해서 가독성이 떨어지는 경우가 많고 로직이 지저분해짐을 느껴 그냥 ‘if ~ else if’문으로 처리해버리는 경우가 많았다.
    switch~case문에 많은 변화가 생겼는데 JAVA17 이전까지는 ‘case’에 여러 값을 지정할 수 있게 되고, 화살표로 리턴값을 지정할 수 있게 되는 등 기존에 불편했던 case문의 기능상 편의성 개선이 많았고 JAVA17 에서는 패턴 매칭 기능, Gaurded Patterns, Null Cases 도 추가되어 기능을 확장시키려는 노력이 엿보인다. 이로써 더욱 깔끔한 코딩이 가능해지고 가독성이 향상되었지만 더 머리아파질 것 같다.
    • case 문에 여러 값 적용
      String java_lts = switch (version) {
          case 8, 11, 17 -> "LTS";
          default -> "NOT LTS";
      };
      
    • 패턴 매칭
      return switch (obj) {
          case Integer i -> "It is an integer";
          case String s -> "It is a string";
          case Employee s -> "It is a Employee";
          default -> "Unknown";
      };
      
    • Gaurded Patterns & Null Cases
      return switch (obj) {
          case Integer i -> "It is an integer";
          case String s -> "It is a string";
          case Employee employee && employee.getDept().equals("IT") -> "IT Employee";
              // case 문에 이런 로직도 사용 가능하리라고는 생각지도 못했다.
          case null -> "It is a null object";	// null case 가 가능해졌다.
          default -> "It is none of the known data types";
      };
      

 

  • Sealed Classes, Sealed Interface (JAVA 15, 17)
    • Sealed 는 ‘봉인된’ 이라는 뜻으로, 지정된 클래스만 상속 혹은 구현이 가능하고 다른 클래스에서는 상속이나 구현이 불가능하다.
    • sealed, final, non-sealed 세 가지 상태가 있다.
	/* 
	 * Game.java 파일
	 * permits 로 선언된 Nintendo, Sony class 만 Game class 를 상속할 수 있다.
	 */
	public sealed class Game permits Nintendo, Sony {}
	...
	
	/* 
	 * Nintendo.java 파일
	 * final 로 선언된 Nintendo Class. 다른 클래스에서 Nintendo 클래스를 상속할 수 없다.
	 */
	public final class Nintendo extends Game {} 	// Game Class 상속가능
	...


	/* 
	 * Sony.java 파일
	 * non-sealed 선언되었기 때문에 Sony class는 아무 클래스에서나 상속 가능하다.
	 */
	public non-sealed class Sony extends Game {}	// Game Class 상속가능
	...


	/* 
	 * Playstation.java 파일
	 * Nintendo 가 final 로 선언된 class 이기 때문에 상속할 수 없다.
	 */
	public class Playstation extends Nintendo {} // Nintendo Class 상속불가
	
	
	/* 
	 * Vita.java 파일
	 * non-sealed class 인 Sony.java 상속이 가능하다
	 */
	public class Vita extends Sony {} // 상속가능
	...
	

 

그 외 변경점들

  • JAVA17은 가장 최신의 LTS 버젼
  • Garbage Collector(GC) 병렬 처리 도입으로 인한 성능 향상 (Java 10)
  • JVM heap 영역을 시스템 메모리가 아닌 다른 종류의 메모리에도 할당 가능 (Java 10)
  • 유니코드 12.1 지원 (Java 13) …
    등등 기술하지 않은 많은 변화들이 있다.

내가 환경 구성을 선택할 수 있는 위치가 아니다보니 새로운 JAVA 버전이 나와도 특별히 관심을 기울이지 않았었다. 이번 기회로 JAVA 버젼별 특징을 정리하고 보니 몇몇 변경점에 관심이 생겼다. 특히 heap 영역을 시스템 메모리가 아닌 다른 종류의 메모리에도 할당 가능한 기능이 눈에 띄는데 이건 더 자세히 공부할 필요가 있을 것 같고, 변경된 switch~case 문 만으로도 JAVA 17 버전을 적용해보고 싶다는 생각이 든다.
회사에서는 우선 새로 구축될 시스템에서 JAVA17을 적용하고 그 이후에 레거시 시스템을 업그레이드 하는 게 작은 위험요소라도 줄일 수 있을 것 같다.

반응형
반응형

개요

Spring-data-jpa를 사용하면 Entity Manager 를 사용하지 않고 쉽게 구현 가능하지만 가끔 Entity Manager로 직접 영속성 컨텍스트를 컨트롤 해야할 필요가 생긴다. 어떤식으로 둘을 함께 사용할 수 있는지 헤딩한 내용을 기록해본다.

  • 목차
    • Spring-data-jpa 와 jpa의 차이
    • 함께 사용해보자
    • 정리

 

Spring-data-jpa 와 jpa의 차이


Spring-data-jpa  JPA를 추상화 시켜둔 개념으로, 개발자가 EntityManager로 직접 접근 없이도 쉽게 개발 할 수 있도록 도와주는 모듈이다. Spring-data-jpa를 구성하는 내부에 Entity Manager가 구현되어 있어 사용자는 Repository Interface를 정의하는 것 만으로 JPA를 손쉽게 사용할 수 있다.

spring-data-jpa Repository


흔히 사용하는 spring-data-jpa Repository 예시

@Repository
public interface workRepository {
	int insertNtisNotice(FeedMessage feedMessage) throws Exception;
	List<FeedMessage> findByMessageLikeOrderByIDDesc(String message) throws Exception;
	int insertNtisNoticeAuto(FeedMessage feedMessage) throws Exception;
	int deleteNtisNoticeAutoCheck() throws Exception;
	List<AccountInfoDTO> selectAccountInfo(AccountInfoDTO accountInfoDTO) throws Exception;
	AccountInfoDTO findByManagerByID(int id) throws Exception;
}

interface 만으로 쿼리에 접근하도록 돕는다. 이것만으로도 반복에 가까운 자바 코드가 줄어든다.

하지만 뭔가 부족하다. 어쩌다 한 두번씩 EntityManager를 사용해야 할 때가 온다.. 그럼 그냥 함께 사용해보자.

 

함께 사용해보자


SpringBoot 프로젝트로 간단하게 구현해보자.

1. 프로젝트 생성하기

스프링부트 프로젝트 만들기 에서 프로젝트를 만들거나, 또는 하단 예제처럼 이클립스에서 New Spring Starter Project 로 프로젝트를 만든다.

설정은 크게 상관없다. Gradle 이나 자바 버전을 8로 선택한 건 단지 내가 익숙해서다.

간단하게 구현 테스트만 해 볼 것이기 때문에 메모리타입 DB를 지원하는 H2 DB와 편의성이 엄청난 Lombok, 당연히 Spring Data Jpa 와 웹서비스를 구현하는 것이므로 Spring Web도 선택한다.

자주 사용하는 항목에 저게 없으면 하단 검색창에서 검색하여 선택하면 된다.

사실 제대로 선택 안해도 상관없다. 프로젝트가 생성된 후 gradle 파일을 직접 수정하고 Refresh gradle project 해주면 제대로 반영된다.

finish 하면 프로젝트가 생성된다.

2. build.gradle 파일

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.4.5'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
	maven { url 'https://repo.spring.io/milestone' }
	maven { url 'https://repo.spring.io/snapshot' }
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

예제를 따라 했다면 위 내용은 버젼만 좀 다르고 거의 같을 것이다.

3. H2 DB 설정하기

spring:
  datasource: 
    url: jdbc:h2:mem:demo #메모리 타입DB로 demo라는 DB에 접근한다는 뜻.
    username: sa          #사용자는 필수 입력사항.
    password:             #패스워드는 선택사항.
    driver-class-name: org.h2.Driver
  h2:
    console:
      enabled: true # H2 DB의 웹 콘솔 사용여부 설정. (http://localhost:8080/h2-console 로 접근)
  jpa:
    database: H2
    show-sql: true # jpa 에서 쿼리 출력여부 설정
    properties:
      hibernate:
        format_sql: true # 쿼리 출력시 정렬 여부 설정 

src/main/resource 경로에 application.yml 파일을 생성하고 위 내용을 입력한다. DB 콘솔 접근법은 하단에서 설명하겠다.

4. 패키지 생성, 소스 작성

위와 같이 패키지 혹은 폴더를 생성하고 다음 파일들을 작성한다. 핵심 내용만 보면

  • Member.java
    public class Member {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name="ID")
      private long id;
    
      private String name;
    
      @Column(nullable=true)
      private Integer age;
    }
    
    간단하게 id와 이름, 나이 컬럼을 사용하려 한다. 실행시 테이블 자동생성을 위해 id에 GeneratedValue 어노테이션과 strategy를 설정해 준다.

 

  • MemberController.java
public class MemberController {
	@Autowired
    private MemberService memberService;

    // 멤버 등록 (spring-data-jpa)
    @PostMapping(value = "/member")
    public String createMember(@RequestBody Member member){
        return memberService.createMember(member);
    }

    // 멤버 등록 (jpa EntityManager)
    @PostMapping(value = "/memberjpa")
    public String createMemberJpa(@RequestBody Member member){
        return memberService.createMemberJpa(member);
    }
	
	// 멤버 조회
    @GetMapping(value = "/member")
    public List<Member> getMember(@RequestParam(required = false, defaultValue = "") String name){
        return memberService.getMemberList(name);
    }
}

두 가지 방식의 멤버 등록을 위한 메써드를 준비하고, 등록이 잘 되었는지 확인할 조회 메서드를 하나 만든다.

 

  • MemberService.java
public class MemberService {

	@Autowired
    private MemberRepository memberRepository;

    // spring-data-jpa
    public String createMember(Member member){
    	memberRepository.save(member); // 사용자 등록 처리
        return "success";
    }

    // jpa
    public String createMemberJpa(Member member){
    	log.info("member name : " + member.getName());
    	memberRepository.createUserAuto(member);
    	return "jpa success";
	}

    public List<Member> getMemberList(String name){
        if(name.isEmpty()) {
            return memberRepository.findAll();
        } else {
        	return memberRepository.findByNameLikeOrderByName(name);
        }
    }
}

컨트롤러와 같은 목적으로 생성한다.

 

  • MemberRepository.java

Repository는 우선 spring-data-jpa를 위해 기본적인 JpaRepository를 상속하는 interface를 만들어준다.

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
	List<Member> findByNameLikeOrderByName(String name);
}

이제 JPA를 만들어본다. JpaRepository는 EntityManager에 직접 접근할 수 없으므로 우회로를 만들어주자.

추후 MemberRepository에 상속하기 위한 interface repository를 만드는데 service에서 jpa용으로 만들어 둔 함수를 사용한다.

public interface MemberCustomReposity {
	String createUserAuto(Member member);
}

그리고 해당 인터페이스를 구현할 MemberCustomReposityImpl 파일도 만든다.

@Transactional(readOnly = true)
public class MemberCustomReposityImpl implements MemberCustomReposity {
	@PersistenceContext	// 영속성 컨택스트를 spring-data-jpa 에서 사용하기 위한 어노테이션
	EntityManager em;

	@Override
	@Transactional
	public String createUserAuto(Member member){
		log.info(member.getName());
		em.persist(member);

		Member member2 = em.find(Member.class, member.getId());
		log.info(member2.getName() + " / " + member2.getId());

		return "실행 완료";
	}
}

아주 단순하게 넘어온 멤버객체 이름을 출력하고, 등록된 값의 id로 데이터를 찾아 정보를 출력해 보았다.

@PersistenceContext를 통해 EntityManager를 가져다 사용하고, 클래스 단의 트랜잭션은 readonly 상태로, 트랜잭선 처리가 필요한 메서드는 @Transactional 어노테이션을 추가해야 EntityManager가 1차캐쉬를 플러쉬 하면서 처리할 수 있다.

여기까지 작성한 내용을 MemberRepository에 추가해 주자.

@Repository
public interface MemberRepository extends JpaRepository<Member, Long>, MemberCustomReposity {
	List<Member> findByNameLikeOrderByName(String name);
}

말은 길었지만 정작 코드는 참 쉽다. 이제 서버를 구동하고 테스트를 해보자.

 

5. 테스트

컨트롤러에 작성한 접근 방식을 이용하여 하나씩 테스트해보자.
먼저 spring-data-jpa 로 등록.

success 응답이 왔다.
다음 JPA EntityManager로 등록.


콘솔 로그도 정상 확인.


제대로 등록 되었는지 조회해보자.

제대로 등록되어 있다.

DB에 직접 붙어서 확인하고 싶다면,

http://localhost:8080/h2-console 로 접속한다.

이와같은 화면을 볼 수 있는데 이것이 h2 DB console 이다. 다른건 그대로 두고, JDBC URL 만 본인 설정에 맞게 변경한다.

연결 테스트 해보고 접속해보자.

그럼 SQL을 직접 작성해 볼 수 있는 창이 보인다. 마음껏 쿼리를 날려보자.

 

정리


  • spring-data-jpa를 기반으로 EntityManager를 위한 repository 를 따로 구현한다.
  • EntityManager를 사용하기 위해 @PersistenceContext 어노테이션을 이용한다.
  • JPA는 트랜잭션 기반으로 동작하기 때문에 EntityManager 설정 시 트랜잭션 설정을 해준다. 정도가 되겠다.

해당 내용의 소스 파일은 Github 에 올려두었다.

하나하나 헤딩하는 과정이 힘들지만 모레알처럼 작은 지식들 하나하나가 쌓여가고 있다고 행복회로를 돌려본다.

반응형
반응형


* deploy 경로
WebApp/deploy/프로젝트명.war

* DB 설정 추가하기 ( standalone.xml  파일 )
  => standalone.xml  파일에서 DB설정 추가
- 경로 : /JBOSS/domains/프로젝트명/configuration/standalone.xml
- <datasources> 에 하단 내용 추가

(오라클 기준)

<datasource jndi-name="java:/jdbc/tb" pool-name="tb" enabled="true" use-java-context="true">
   <connection-url>jdbc:oracle:thin:@192.168.200.119:1521:XE</connection-url>
   <driver>oracle</driver>
   <pool>
     <min-pool-size>10</min-pool-size>
     <max-pool-size>15</max-pool-size>
     <prefill>true</prefill>
   </pool>
   <security>
     <user-name>tb</user-name>
     <password>1234</password>
   </security>
   <validation>
     <check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
     <validate-on-match>false</validate-on-match>
     <background-validation>true</background-validation>
     <background-validation-millis>10000</background-validation-millis>
     <use-fast-fail>false</use-fast-fail>
   </validation>
     <statement>
     <prepared-statement-cache-size>100</prepared-statement-cache-size>
     <share-prepared-statements>true</share-prepared-statements>
   </statement>
</datasource>

 

 -- <Drivers> 에 추가

(오라클 기준)

<driver name="oracle" module="com.oracle">
   <driver-class>oracle.jdbc.OracleDriver</driver-class>
</driver>



* 오라클 드라이버 추가

/JBOSS/jboss-eap-7.4/modules/system/layers/base/com/ 

위 경로를 보면 다양한 DB연결 api들이 있다. 해당 경로에 oracle 폴더가 있는지 확인하고 없다면 /oracle/main/ 추가.

ojdbc 등 DB접속에 필요한 파일을 복사해 넣고, 넣은 파일들을 기준으로 

동일 폴더에 module.xml 파일 생성 후 하단 내용 추가.

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.oracle">
    <resources>
	     <resource-root path="ojdbc6-11.2.0.3.jar" />
	     <resource-root path="ojdbc8-19.8.0.0.jar" />
         <resource-root path="orai18n-19.3.0.0.jar" />
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>

resource-root 부분을 파일에 맞게 수정


* Web.xml
경로 : 프로젝트 소스 내 /WEB-INF/web.xml 파일 수정

<resource-ref>
    <description>Datasource Contents Server</description>
    <res-ref-name>jdbc/tb</res-ref-name> <!-- JNDI 명 -->
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>



* jboss-web.xml 
경로 : 프로젝트 소스 내 /WEB-INF/jboss-web.xml
jboss-web.xml  수정. (없으면 생성)

<!DOCTYPE jboss-web PUBLIC
   "-//JBoss//DTD Web Application 5.0//EN"
   "http://www.jboss.org/j2ee/dtd/jboss-web_5_0.dtd">
   
<jboss-web> 
    <resource-ref>
        <res-ref-name>jdbc/jdbc/tb</res-ref-name>
        <jndi-name>java:/jdbc/tb</jndi-name> <!-- standalone.xml 파일의 JNDI-NAME -->
    </resource-ref>
</jboss-web>

 

반응형

+ Recent posts