'JAVA > Java' 카테고리의 다른 글
java Stream 사용법 (0) | 2019.07.11 |
---|---|
Intellij Rest Client (0) | 2019.07.11 |
REST 개념 (0) | 2019.03.21 |
Spring Boot microservice (0) | 2019.03.05 |
메서드, 클래스 명명규칙 어떡하면 좋을까? (0) | 2017.07.04 |
java Stream 사용법 (0) | 2019.07.11 |
---|---|
Intellij Rest Client (0) | 2019.07.11 |
REST 개념 (0) | 2019.03.21 |
Spring Boot microservice (0) | 2019.03.05 |
메서드, 클래스 명명규칙 어떡하면 좋을까? (0) | 2017.07.04 |
익숙해지면, 참 편하고 좋은 툴!
그런데, 어느정도 사용하다보면 느려지는 현상 발견!
알고보니 프로그램의 메모리 사용량을 늘려주어야 한단다!
1. [Help] - [Edit Custom VM Options...] 클릭 2. Xms, Xmx 수치를 높여준다. 3. IntelliJ를 다시 켠다. 완료.
1. IntelliJ를 모두 끈다. 2. IntelliJ가 설치된 폴더 안의 bin폴더로 이동한다.C:\Program Files (x86)\JetBrains\IntelliJ IDEA x.x.x\bin 3. 다음 파일을 편집기로 연다.
idea.exe.vmoptions
idea64.exe.vmoptions
4. Xms, Xmx 수치를 높여주고 저장한다. 5. IntelliJ를 켠다. 완료.
저의 사양은 RAM 24g이며 IntelliJ가 최대 2048m까지 할당 할 수 있도록 설정하였다.
-Xms128m -Xmx2048m -XX:MaxPermSize=1024m -XX:ReservedCodeCacheSize=512m -XX:+UseCodeCacheFlushing -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true
저의 사양은 RAM 24g이며 IntelliJ가 최대 3072m까지 할당 할 수 있도록 설정하였다.
-Xms2048m -Xmx3072m -XX:ReservedCodeCacheSize=500m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Dfile.encoding=UTF-8
IntelliJ의 하단 오른쪽에 메모리 할당량이 표시된다.
하지만, 버전에 따라서는 기본으로 보여지지 않는 경우가 있는데,
옵션을 통해 표시할 수 있다.
[File] - [Settings]에서 'show memory indicator'로 검색해서 [ v ] 체크해주면 나타난다.
[File] - [Settings] - [Appearance & Behavior] - [Appearance] - [ v ] Show memory indicator
인텔리제이 메모리 힙 늘리기: https://www.jetbrains.com/help/idea/2016.2/increasing-memory-heap.html
Is it possible to show heap memory size in intellij IDE (Android Studio)?: http://stackoverflow.com/questions/36691118/is-it-possible-to-show-heap-memory-size-in-intellij-ide-android-studio
출처: https://forgiveall.tistory.com/405 [하하하하하]
RestTemplate VS WebClient (0) | 2021.02.24 |
---|---|
비동기, 동기, 블로킹, 논블로킹 (0) | 2021.02.19 |
JAVA11 (0) | 2019.10.04 |
Oracle JDK 라이센스 전환 (0) | 2019.10.04 |
NAVER Search Ad - ADExtensions (0) | 2019.08.13 |
spring 3.0 부터 지원한다. 스프링에서 제공하는 http 통신에 유용하게 쓸 수 있는 템플릿이며, HTTP 서버와의 통신을 단순화하고 RESTful 원칙을 지킨다. jdbcTemplate 처럼 RestTemplate 도 기계적이고 반복적인 코드들을 깔끔하게 정리해준다. 요청보내고 요청받는데 몇줄 안될 정도..
jdk 1.2 부터 내장되어 있으며, java.net 패키지에 있다. URL의 내용을 읽어오거나, URL 주소에 GET, POST로 데이터를 전달 할 때 사용한다. 또한 http 프로토콜 이외에도 가능하다.(file 등) 보통 아래와 같이 사용한다.
3.x일 땐 apache commons 의 프로젝트였다가 승급해서, 아파치 탑 프로젝트가 되었다. 4.x부터는 Apache HttpComponents 로 불린다. maven dependency 를 설정하거나, http://hc.apache.org/downloads.cgi 에서 다운로드할 수 있다. org.apache.http 패키지에 있다.보통 아래처럼 사용한다.
org.springframework.http.client 패키지에 있다. HttpClient는 HTTP를 사용하여 통신하는 범용 라이브러리이고, RestTemplate은 HttpClient 를 추상화(HttpEntity의 json, xml 등)해서 제공해준다. 따라서 내부 통신(HTTP 커넥션)에 있어서는 Apache HttpComponents 를 사용한다. 만약 RestTemplate 가 없었다면, 직접 json, xml 라이브러리를 사용해서 변환해야 했을 것이다.
기본 생성 : RestTemplate restTemplate = getRestTempalte();
설정 생성 :
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(5000); // 읽기시간초과, ms
factory.setConnectTimeout(3000); // 연결시간초과, ms
HttpClient httpClient = HttpClientBuilder.create()
.setMaxConnTotal(100) // connection pool 적용
.setMaxConnPerRoute(5) // connection pool 적용
.build();
factory.setHttpClient(httpClient); // 동기실행에 사용될 HttpClient 세팅
RestTemplate restTemplate = new RestTemplate(factory);
언젠가 만날 것 같아서 기록.. RestTemplate 은 기본적으로 connection pool 을 사용하지 않는다. 따라서 연결할 때 마다, 로컬 포트를 열고 tcp connection 을 맺는다. 이때 문제는 close() 이후에 사용된 소켓은 TIME_WAIT 상태가 되는데, 요청량이 많다면 이런 소켓들을 재사용하지 못하고 소켓이 오링나서 응답이 지연될 것이다.
이런 경우 connection pool 을 사용해서 해결할 수 있는데, DBCP마냥 소켓의 갯수를 정해서 재사용하는 것이다. RestTemplate 에서 connection pool 을 적용하려면, 위와 같이 HttpClient 를 만들고 setHttpClient() 를 해야한다.
RestTemplate Method | HTTP Method | 설명 |
---|---|---|
execute | Any | |
exchange | Any | 헤더세팅해서 HTTP Method로 요청보내고 ResponseEntity로 반환받음 |
getForObject | GET | get 요청을 보내고 java object로 매핑받아서 반환받음 |
getForEntity | GET | get 요청을 보내고 ResponseEntity로 반환받음 |
postForLocation | POST | post 요청을 보내고 java.net.URI 로 반환받음 |
postForObject | POST | post 요청을 보내고 ResponseEntity로 반환받음 |
put | PUT | |
delete | DELETE | |
headForHeaders | HEAD | |
optionsForAllow | OPTIONS |
다양한 방법이 있다.
ForObject 를 사용할때, 응답 xml이나 json 에 맞는 java object(Class responseType)가 필요하다. @XmlElement 를 사용하거나 @JsonProperty 등을 사용하여 매핑해줘야한다.
DefaultResponseErrorHandler를 사용하여 HTTP Error 를 제어한다. restTemplate.setErrorHandler 를 통해 커스텀 핸들러를 등록할 수 있다.
RestTemplate 는 동기처리에 사용된다. 비동기 처리는 org.springframework.web.client.AsyncRestTemplate 를 사용해야 한다. 언젠가 쓸 일이 오겠지..
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
public class RestTemplateEx {
public static void main(String[] args) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(5000); // 읽기시간초과, ms
factory.setConnectTimeout(3000); // 연결시간초과, ms
HttpClient httpClient = HttpClientBuilder.create()
.setMaxConnTotal(100) // connection pool 적용
.setMaxConnPerRoute(5) // connection pool 적용
.build();
factory.setHttpClient(httpClient); // 동기실행에 사용될 HttpClient 세팅
RestTemplate restTemplate = new RestTemplate(factory);
String url = "http://testapi.com/search?text=1234"; // 예제니까 애초에 때려박음..
Object obj = restTemplate.getForObject("요청할 URI 주소", "응답내용과 자동으로 매핑시킬 java object");
System.out.println(obj);
}
}
출처: https://sjh836.tistory.com/141 [빨간색코딩]
[Spring JPA] ORM과 JPA 그리고 Hibernate (0) | 2019.08.20 |
---|---|
Spring boot yml 파일 사용 (1) | 2019.03.21 |
Mapper XML 파일 (0) | 2016.06.23 |
logback 설정 (0) | 2016.06.17 |
iBatis MyBatis 차이 (0) | 2016.06.17 |
Spring boot의 설정 파일 YAML을 사용하는 방법
대부분의 애플리케이션에서 설정과 관련된 변수들은 보통 파일에다가 쓰고 읽어오는 방식으로 프로그래밍한다.
외부에 설정파일을 넣을 수도 있고 내부적으로 프로젝트에 넣을 수도 있다.
해당 파일들은 포맷(.properties, .ini 등)도 다양하다.
스프링 부트에서도 설정에 대한 내용을 다양한 파일에 적고 읽어와 사용하는데 그 중에서 가장 적합하고 스프링 부트에서 권장하는 형식인 yaml에 대해서 간단히 설명하고 사용해본다.
왜 YAML 이어야 하는가?
-> 사람이 보기 편하다!
1 2 3 4 5 6 7 | environments: dev: url: http://dev.example.com name: Developer Setup prod: url: http://another.example.com name: My Cool App |
[YAML]
1 2 3 4 | environments.dev.url=http://dev.example.com environments.dev.name=Developer Setup environments.prod.url=http://another.example.com environments.prod.name=My Cool App |
[Properties]
똑같은 설정이지만 yaml을 사용할 경우 위와 같이 들여쓰기(띄어쓰기)로 구분하여 사람이 보기가 편하다. 곧 관리가 편리하다.
또한 아래와 같이 리스트로 표현하고자 할 때는 "-" (대쉬) 하나로 쓸 수 있다.
1 2 3 4 | my: servers: - dev.example.com - another.example.com |
뿐만 아니라 profile을 지정해서 환경에 따라 설정값을 다르게 가져갈 수 있는 장점이 있고, 하나의 파일에서 마치 여러개의 설정파일을 쓰는 듯하게 구분하여 사용할 수 있다. (아래처럼 "---"를 써서 구분)
1 2 3 4 5 6 7 8 9 10 11 12 | server: address: 192.168.1.100 --- spring: profiles: development server: address: 127.0.0.1 --- spring: profiles: production & eu-central server: address: 192.168.1.120 |
여러모로 장점이 많아서 잘 쓰면 아주 유용하게 사용할 수 있다.
굳이 단점을 말하자면 문법(?)이 아주 약간 엄격한 것이 단점이다. 예를들면 하위 계층을 표현할 때 tab들여쓰기가 아닌 공백문자를 써야한다든가, :(콜론) 다음에 공백 한칸이 있어야한다든가하는 문제가 있다.
이런 문제는 몇 번 삽질해보면 금방 깨닫게 되고 사용법을 아래에서 간단히 익히면 해결될 문제다.
진짜로 yaml 사용(테스트) 해보기
example 프로젝트를 만들어 보았다.
[프로젝트 구조]
프로젝트 구조는 위와 같이 구성하였다. 기존에 있던 application.properties는 지우고 classpath인 src/main/resources에 application.yml 파일을 생성했다.
참고로 .yml = .yaml 이다. 또한 스프링부트에서는 자동으로 classpath안에 있는 설정파일을 찾게 되어있다.
위 그림은 spring-boot-starter-parent의 pom.xml의 일부로, 보다시피 application이 접두사(prefix?)로 붙은 설정파일을 classpath이하의 어떤 디렉토리에 있든 .yml, .yaml, .properties 순서로 찾아서 읽는다.
1 2 3 4 | env: servers: - dev.example.com - prod.example.com |
[application.yml]
보다시피 env 밑에 servers가 있는데 그 안에 List형태로 두 개의 String값이 들어가 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package com.example.demo.config; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix="env") public class TestConfig { //getter, setter private List<String> servers = new ArrayList<String>(); public List<String> getServers() { return this.servers; } public void setServers(List<String> servers) { this.servers = servers; } } |
[TestConfig.java]
스프링 부트가 설정파일에서 읽어온 값을 관리할 객체를 나타낸 것이다.
@ConfigurationProperties로 설정 파일에서 읽어온 값을 해당 클래스에 바인딩할 것이고 prefix 부분을 두어서 필요한 부분만 가져올 수도 있다.
따라서 prefix인 "env" 아래에 있는 servers라는 List만 가져올 것이므로 클래스에 있는 변수의 자료형도 List<String>으로 설정해서 가져왔다.
또한 @Component로 설정해서 bean객체로 등록할 수 있게 했다.
bean객체로 등록하게되면 알다시피 스프링 부트 어디에든(?) bean객체를 주입받아 설정 값들을 사용할 수 있게 된다.
(* 참고로 스프링부트에서는 @SpringBootApplication가 쓰인 메인클래스가 있는 최상위 패키지 이하의 패키지에서 등록된 모든 Component를 스캔한다.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.example.demo.config.TestConfig; @RestController public class TestController { @Autowired TestConfig testConfig; @RequestMapping("/") public String test() { return testConfig.getServers().get(0) + " / " + testConfig.getServers().get(1); } } |
[TestController.java]
테스트를 위해 RestController를 만들었다.
또한 아까 등록한 bean객체를 주입받기 위해 @Autowired를 사용했고 루트경로(localhost:8080)로 들어왔을 때 해당 값을 리턴해서 테스트 해보았다.
[결과] -> 잘 나왔다.
변형된 사용법
무난하게 사용하는 방법은 위에서 설명한 것과 같고 이제는 조금 변형된 yaml파일의 경우에 설정 값을 가져오는 방법을 알아보려고한다.
1. application.yml이 아닌 다른 파일을 사용할 경우
특별한 경우가 아니면 application.yml 혹은 applicationXXX.yml 이런식으로 사용하면 자동으로 찾아진다.
그러나 abc.yml 같이 이름을 다르게 지정하고 싶고 경로도 다르게 하고 싶으면 아래와 같이 쓰면된다.
1 | @ConfigurationProperties(locations="classpath:abc.yml", prefix="env") |
2. 여러 자료구조를 사용할 경우
바인딩이 자연스럽게 된다.
1 2 3 4 5 | env: servers: helloworld obj: number: 10 sec: 10s |
[applicatoin.yml]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package com.example.demo.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix="env") public class TestConfig { private String servers; private Sample obj; public String getServers() { return servers; } public void setServers(String servers) { this.servers = servers; } public Sample getObj() { return obj; } public void setObj(Sample obj) { this.obj = obj; } } | cs |
[TestConfig.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.example.demo.config; import java.time.Duration; public class Sample { private int number; private Duration sec; public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public Duration getSec() { return sec; } public void setSec(Duration sec) { this.sec = sec; } } |
[Sample.java]
[결과]
역시 잘 들어가 있다.
3. profile로 환경에 따른 설정파일 세팅하기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | spring: profiles: active: local # 기본 환경 선택 # local 환경 --- spring: profiles: local datasource: data: classpath:data-h2.sql # 시작할때 실행시킬 script jpa: show-sql: true hibernate: ddl-auto: create-drop h2: console: enabled: true # 운영 환경 --- spring: profiles: set1 server: port: 8081 |
<출처 : http://jojoldu.tistory.com/269>
위와 같이 spring.profiles.active: local로 하면 profiles가 :local인 설정이 적용되고 set1으로하면 set1인 설정이 적용된다.
default 환경을 설정해둘 수 있고 active되는 것마다 바꾸면 되니 개발하고 배포할 때 아주 편리하게 할 수 있다.
4. 여러 파일을 하나의 yml파일로 관리하기
이것은 3번처럼 그냥 ---으로 나누면 다른 파일에서 불러온 것처럼 쓸 수 있다. (고로 생략..)
* 참고사항
- 꼭 String이 아니어도 binding이 유연하게 적용된다.
- yaml을 작성할 때는 kebab case(중간에 -를 쓰는것)를 사용하는 것을 권장한다. ex) jeong-pro.server.ip: ...
출처: https://jeong-pro.tistory.com/159 [기본기를 쌓는 정아마추어 코딩블로그]
[Spring JPA] ORM과 JPA 그리고 Hibernate (0) | 2019.08.20 |
---|---|
RestTemplate (정의, 특징, URLConnection, HttpClient, 동작원리, 사용법, connection pool 적용) (0) | 2019.03.21 |
Mapper XML 파일 (0) | 2016.06.23 |
logback 설정 (0) | 2016.06.17 |
iBatis MyBatis 차이 (0) | 2016.06.17 |
REST가 무엇인가?
REST는 분산 시스템 설계를 위한 아키텍처 스타일이다.
아키텍처 스타일이라는건 쉽게 말하면 제약 조건의 집합이라고 보면 된다.
RESTful은 무엇인가?
RESTful은 위의 제약 조건의 집합(아키텍처 스타일, 아키텍처 원칙)을 모두 만족하는 것을 의미한다.
REST라는 아키텍처 스타일이 있는거고 RESTful API라는 말은 REST 아키텍처 원칙을 모두 만족하는 API라는 뜻이다.
우리가 REST와 RESTful을 동일한 의미로 사용하곤 하는데 엄격하게는 다르다는 것을 알 수 있다.
->이로써 REST와 RESTful, RESTful API가 무엇인지, 어떻게 다른지를 말할 수 있게 되었다.
REST가 필요한 이유는 뭘까?
1. 위에서 말한 것과 같이 분산 시스템을 위해서다.
거대한 애플리케이션을 모듈, 기능별로 분리하기 쉬워졌다. RESTful API를 서비스하기만 하면 어떤 다른 모듈 또는 애플리케이션들이라도 RESTful API를 통해 상호간에 통신을 할 수 있기 때문이다.
2. WEB브라우저 외의 클라이언트를 위해서다. (멀티 플랫폼)
웹 페이지를 위한 HTML 및 이미지등을 보내던 것과 달리 이제는 데이터만 보내면 여러 클라이언트에서 해당 데이터를 적절히 보여주기만 하면 된다.
예를 들어 모바일 애플리케이션으로 html같은 파일을 보내는 것은 무겁고 브라우저가 모든 앱에 있는 것은 아니기 때문에 알맞지 않았는데 RESTful API를 사용하면서 데이터만 주고 받기 때문에 여러 클라이언트가 자유롭고 부담없이 데이터를 이용할 수 있다.
서버도 요청한 데이터만 깔끔하게 보내주면되기 때문에 가벼워지고 유지보수성도 좋아졌다.
REST의 구성 요소
HTTP URI = 자원
HTTP Method = 행위
MIME Type = 표현 방식
1 2 | GET /100 HTTP/1.1 Host : jeong-pro.tistory.com | cs |
위와 같은 Request 메세지가 있으면 URI자원은 "/100" 이고, HTTP Method는 "GET" 이다.
MIME 타입은 보통 Response Http header 메세지에 Content-type으로 쓰인다. 여기서는 없다.
그러면 이해하기를 jeong-pro.tistory.com 서버에 /100 이라는 자원을 GET(조회)하고 싶다는 요청으로 해석이 가능하다. 이게 REST 방식을 이용한 Request 예시다. (참고로 이것은 이해를 위한 것일 뿐 RESTful 하다고는 못한다.)
1 2 3 4 | HTTP/1.1 200 OK Content-Type : application/json-patch+json [{"title": "helloworld", "author": "jeong-pro"}] |
이런 Response가 왔다고 해보자.
그러면 Content-Type을 보고 클라이언트는 IANA라는 타입들의 명세를 모아놓은 사이트에 가서 application/json-patch+json 이라는 타입의 명세를 확인하고 아래 Body의 내용이 json타입이구나를 알 수 있는 것이다.
REST는 알겠고 그러면 그 제약 조건이 뭔데요?
1. Client/Server
2. Stateless : 각 요청에 클라이언트의 context가 서버에 저장되어서는 안된다.
3. Cacheable : 클라이언트는 응답을 캐싱할 수 있어야 한다.
4. Layered System : 클라이언트는 서버에 직접 연결되었는지 미들웨어에 연결되었는지 알 필요가 없어야 한다.
5. Code on demand(option) : 서버에서 코드를 클라이언트에게 보내서 실행하게 할 수 있어야 한다.
6. uniform interface : 자원은 유일하게 식별가능해야하고, HTTP Method로 표현을 담아야 하고, 메세지는 스스로를 설명(self-descriptive)해야하고, 하이퍼링크를 통해서 애플리케이션의 상태가 전이(HATEOAS)되어야 한다.
왜 uniform interface에 강조가 되어있냐면, 1~5번의 제약 조건은 HTTP를 기반으로하는 REST는 HTTP에서 이미 충분히 지켜지고 있는 부분이라서 비교적 덜 주의를 기울여도 된다.
RESTful하려면 저 uniform interface를 잘 지켜야 한다.
그 중에서도 HATEOAS와 self-descriptive를 잘 지켜야 한다.
필자가 주로 쓰는 Spring에는 spring-data-rest, spring hateoas, spring-rest-doc으로 두 제약을 지키기위해 사용할 수 있는 라이브러리가 있다. (이 포스트는 면접을 위한 포스트일 뿐 사용법과 테스트는 다른 포스트에서 한다.)
HATEOAS는 Link 라는 HTTP 헤더에 다른 리소스를 가리켜 주는 값을 넣는 방법으로 해결한다.
1 2 3 4 5 6 7 8 | HTTP/1.1 200 OK Content-Type : application/json Link : </spring/1>; rel="previous", </spring/3>; rel="next"; { "title" : "spring의 모든 것" "author" : "jeong-pro" } | cs |
위와 같이 해당 정보에서 다른 정보로 넘어갈 수 있는 하이퍼링크를 명시해야 한다는 것이다.
완벽한 REST는 무엇일까? WEB이다.
어떤 Application이 생겼다고 브라우저는 버전을 업데이트할 필요가 없고, 브라우저가 해당 application으로 어떻게 요청하는지를 알게 해야할 필요가 없다.
* 장점
- 메세지를 단순하게 표현할 수 있고 WEB의 원칙인 확장에 유연하다. (멀티플랫폼)
- 별도의 장비나 프로토콜이 필요없이 기존의 HTTP 인프라를 이용할 수 있다. (사용이 용이함)
- server, client를 완전히 독립적으로 구현할 수 있다.
* 단점
- 표준, 스키마가 없다. 결국은 API 문서가 만들어지는 이유다.
- 행위에 대한 메소드가 제한적이다. (GET, POST, PUT, DELETE, HEAD, ...)
* REST는 분산 시스템 설계를 위한 이키텍처 스타일이라고 했다.
마이크로서비스라는 말을 들어보았을 것이다. 이 쪽으로 질문이 연계될 수 있다.
RESTful API를 이용해서 하나의 큰 서비스 애플리케이션을 여러 모듈화된 작은 서비스 애플리케이션(마이크로 서비스)들로 나눌 수 있게 됐기 때문이다.
* REST를 공부하니까 URI와 URL의 차이점에 대해서도 이해할 수 있게되었다.
Uniform Resource Identifier, Uniform Resource Locator
REST에서는 모든 것을 Resource로 표현한다. 그리고 그 자원은 유일한 것을 나타낸다. Identifier, 식별자라는 것이다.
반면에 과거의 웹에서는 Identifier의 개념이 따로 필요없었다. html같은 파일들을 주고 받았기 때문에 파일의 위치를 가리키는 Locator를 썼다고 이해하면 된다.
URI가 파일뿐만 아니라 여러 자원들 까지도 포함하는 개념으로 이해할 수 있다.
* 자세한 명세를 알고 싶은 사람은 마이크로소프트에서 발표한 REST 가이드라인을 보면 좋을 것이다.
https://github.com/Microsoft/api-guidelines/blob/vNext/Guidelines.md
참고 사이트
https://www.youtube.com/watch?v=RP_f5dMoHFc
https://spring.io/understanding/REST
출처: https://jeong-pro.tistory.com/180 [기본기를 쌓는 정아마추어 코딩블로그]
Intellij Rest Client (0) | 2019.07.11 |
---|---|
Intellij 셋팅 파일 (0) | 2019.07.09 |
Spring Boot microservice (0) | 2019.03.05 |
메서드, 클래스 명명규칙 어떡하면 좋을까? (0) | 2017.07.04 |
이클립스 실행 인자 입력 받기 (0) | 2016.11.02 |
NOTE: Revised June 2018
A simple example of setting up a microservices system using Spring, Spring Boot and Spring Cloud.
Microservices allow large systems to be built up from a number of collaborating components. It does at the process level what Spring has always done at the component level: loosely coupled processes instead of loosely coupled components.
For example imagine an online shop with separate microservices for user-accounts, product-catalog order-processing and shopping carts:
Inevitably there are a number of moving parts that you have to setup and configure to build such a system. How to get them working together is not obvious - you need to have good familiarity with Spring Boot since Spring Cloud leverages it heavily, several Netflix or other OSS projects are required and, of course, there is some Spring configuration “magic”!
In this article I aim to clarify how things work by building the simplest possible system step-by-step. Therefore, I will only implement a small part of the big system - the user account service.
The Web-Application will make requests to the Account-Servicemicroservice using a RESTful API. We will also need to add a discovery service – so the other processes can find each other.
The code for this application is here: https://github.com/paulc4/microservices-demo.
The description of how it works is deliberately detailed. Impatient readers may prefer to simply look at the code. Note that it contains three microservices in a single project.
This article only discusses a minimal system. For more information, you might like to read Josh Long’s blog article Microservice Registration and Discovery with Spring Cloud and Netflix’s Eureka which shows running a complete microservice system on Cloud Foundry.
The Spring Cloud projects are here.
Book your place at SpringOne2 Platform in Washington DC, USA this September - simply the best opportunity to find out first hand all that’s going on and to provide direct feedback. The name has changed, from Spring One, to reflect the growth of Spring in platform services (such as the Spring Cloud projects).
A number of changes since I originally wrote this blog:
@LoadBalanced
- how this works has changed since the Brixton release-train (Spring Cloud 1.1.0.RELEASE).AccountsConfiguration
.spring-cloud-starter-netflix-eureka-server
.Previous version, using Spring Boot 1.5.10 and Spring Cloud Edgeware SR3, is available as git tag v1.2.0.
OK, let’s get started …
When you have multiple processes working together they need to find each other. If you have ever used Java’s RMI mechanism you may recall that it relied on a central registry so that RMI processes could find each other. Microservices has the same requirement.
The developers at Netflix had this problem when building their systems and created a registration server called Eureka (“I have found it” in Greek). Fortunately for us, they made their discovery server open-source and Spring has incorporated into Spring Cloud, making it even easier to run up a Eureka server. Here is the complete discovery-server application:
@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistrationServer {
public static void main(String[] args) {
// Tell Boot to look for registration-server.yml
System.setProperty("spring.config.name", "registration-server");
SpringApplication.run(ServiceRegistrationServer.class, args);
}
}
It really is that simple!
Spring Cloud is built on Spring Boot and utilizes parent and starter POMs. The important parts of the POM are:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<!-- Setup Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<!-- Setup Spring MVC & REST, use Embedded Tomcat -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<!-- Spring Cloud starter -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<!-- Eureka for service registration -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<!-- Spring Cloud dependencies -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
This POM has changed since I originally wrote the article to use Spring Boot as its parent not Spring Cloud. Spring Cloud dependencies are provided via the dependency management section.
An sample gradle build file is also included in the github code.
Note: Finchley.RELEASE is the current "release train" - a set of co-ordinated releases -- see note on Spring Cloud home page.
By default Spring Boot applications look for an application.properties
or application.yml
file for configuration. By setting the spring.config.name
property we can tell Spring Boot to look for a different file - useful if you have multiple Spring Boot applications in the same project - as I will do shortly.
This application looks for registration-server.properties
or registration-server.yml
. Here is the relevant configuration from registration-server.yml
:
# Configure this Discovery Server
eureka:
instance:
hostname: localhost
client: # Not a client, don't register with yourself (unless running
# multiple discovery servers for redundancy)
registerWithEureka: false
fetchRegistry: false
server:
port: 1111 # HTTP (Tomcat) port
By default Eureka runs on port 8761, but here we will use port 1111
instead. Also by including the registration code in my process I might be a server or a client. The configuration specifies that I am not a client and stops the server process trying to register with itself.
Spring Cloud also supports Consul as an alternative to Eureka. You start the Consul Agent (its registration server) using a script and then clients use it to find their microservices. For details, see this blog article or project home page.
Try running the RegistrationServer now (see below for help on running the application). You can open the Eureka dashboard here: http://localhost:1111 and the section showing Applications will be empty.
From now on we will refer to the discovery-serversince it could be Eureka or Consul (see side panel).
A microservice is a stand-alone process that handles a well-defined requirement.
When configuring applications with Spring we emphasize Loose Coupling and Tight Cohesion, These are not new concepts (Larry Constantine is credited with first defining these in the late 1960s - reference) but now we are applying them, not to interacting components (Spring Beans), but to interacting processes.
In this example, I have a simple Account management microservice that uses Spring Data to implement a JPA AccountRepository
and Spring REST to provide a RESTful interface to account information. In most respects this is a straightforward Spring Boot application.
What makes it special is that it registers itself with the discovery-server at start-up. Here is the Spring Boot startup class:
@EnableAutoConfiguration
@EnableDiscoveryClient
@Import(AccountsWebApplication.class)
public class AccountsServer {
@Autowired
AccountRepository accountRepository;
public static void main(String[] args) {
// Will configure using accounts-server.yml
System.setProperty("spring.config.name", "accounts-server");
SpringApplication.run(AccountsServer.class, args);
}
}
The annotations do the work:
@EnableAutoConfiguration
- defines this as a Spring Boot application.@EnableDiscoveryClient
- this enables service registration and discovery. In this case, this process registers itself with the discovery-server service using its application name (see below).@Import(AccountsWebApplication.class)
- this Java Configuration class sets up everything else (see below for more details).What makes this a microservice is the registration with the discovery-server via @EnableDiscoveryClient
and its YML configuration completes the setup:
# Spring properties
spring:
application:
name: accounts-service
# Discovery Server Access
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
# HTTP Server
server:
port: 2222 # HTTP (Tomcat) port
Note that this file
accounts-service
. This service registers under this name and can also be accessed by this name - see below.Run the AccountsServiceapplication now and let it finish initializing. Refresh the dashboard http://localhost:1111 and you should see the ACCOUNTS-SERVICE listed under Applications. Registration takes up to 30 seconds (by default) so be patient - check the log output from RegistrationService
Warning: Do not try to display XML output using the internal web-viewer of Eclipse/STS because it cannot do so. Use your favorite web browser instead.
For more detail, go here: http://localhost:1111/eureka/apps/ and you should see something like this:
<applications>
<versions__delta>1</versions__delta>
<apps__hashcode>UP_1_</apps__hashcode>
<application>
<name>ACCOUNTS-SERVICE</name>
<instance>
<hostName>autgchapmp1m1.corp.emc.com</hostName>
<app>ACCOUNTS-SERVICE</app>
<ipAddr>172.16.84.1</ipAddr><status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">3344</port>
<securePort enabled="false">443</securePort>
...
</instance>
</application>
</applications>
Alternatively go to http://localhost:1111/eureka/apps/ACCOUNTS-SERVICE and see just the details for AccountsService - if it’s not registered you will get a 404.
Registration Time: Registration takes up to 30s because that is the default client refresh time. You can change this by setting the eureka.instance.leaseRenewalIntervalInSeconds
property to a smaller number (in the demo application I have set it to 5). This is not recommended in production. See also.
eureka:
instance:
leaseRenewalIntervalInSeconds: 5 # DO NOT DO THIS IN PRODUCTION
Registration Id: A process (microservice) registers with the discovery-service using a unique id. If another process registers with the same id, it is treated as a restart (for example some sort of failover or recovery) and the first process registration is discarded. This gives us the fault-tolerant system we desire.
To run multiple instances of the same process (for load-balancing and resilience) they need to register with a unique id. When I first wrote this blog, that was automatic and since the Brixtonrelease-train, it is again.
Under the Angel release train, the instance-id, used by a client to register with a discovery server, was derived from the client’s service name (the same as the Spring application name) and also the client’s host name. The same processes running on the same host would therefore have the same id, so only one could ever register.
Fortunately you could set the id property manually via the client’s Eureka metadata map, like this:
eureka:
instance:
metadataMap:
instanceId: ${spring.application.name}:${spring.application.instance_id:${server.port}}
Since the Brixton release train, this is now the default. So what does it do?
We are setting the instanceId
to application-name:instance_id
, but if instance_id
is not defined, we will use application-name::server-port
instead. Note that the spring.application.instance_id
is only set when using Cloud Foundry but it conveniently provides a unique id number for each instance of the same application. We can do something similar when running elsewhere by using the server-port (since different instances on the same machine must listen on different ports. Another example you will often see is ${spring.application.name}:${spring.application.instance_id:${random.value}}
but I personally find using the port number makes each instance easy to identify - the random values are just long strings that don’t mean anything.
Note: The syntax ${x:${y}}
is Spring property shorthand for ${x} != null ? ${x} : ${y}
.
Since the Brixton release there is also a dedicated property for this:
eureka:
instance:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
To consume a RESTful service, Spring provides the RestTemplate
class. This allows you to send HTTP requests to a RESTful server and fetch data in a number of formats - such as JSON and XML.
Note: The Accounts microservice provides a RESTful interface over HTTP, but any suitable protocol could be used. Messaging using AMQP or JMS is an obvious alternative (in which case the Discovery Server is no longer needed - instead processes need to know the names of the queues to talk to, consider using the Spring Cloud Configuration Server for this).
Which formats can be used depends on the presence of marshaling classes on the classpath - for example JAXB is always detected since it is a standard part of Java. JSON is supported if Jackson jars are present in the classpath.
A microservice (discovery) client can use a RestTemplate
and Spring will automatically configure it to be microservice aware (more of this in a moment).
Here is part of the WebAccountService
for my client application:
@Service
public class WebAccountsService {
@Autowired // NO LONGER auto-created by Spring Cloud (see below)
@LoadBalanced // Explicitly request the load-balanced template
// with Ribbon built-in
protected RestTemplate restTemplate;
protected String serviceUrl;
public WebAccountsService(String serviceUrl) {
this.serviceUrl = serviceUrl.startsWith("http") ?
serviceUrl : "http://" + serviceUrl;
}
public Account getByNumber(String accountNumber) {
Account account = restTemplate.getForObject(serviceUrl
+ "/accounts/{number}", Account.class, accountNumber);
if (account == null)
throw new AccountNotFoundException(accountNumber);
else
return account;
}
...
}
Note that my WebAccountService
is just a wrapper for the RestTemplate fetching data from the microservice. The interesting parts are the serviceUrl
and the RestTemplate
.
As shown below, the serviceUrl
is provided by the main program to the WebAccountController
(which in turn passes it to the WebAccountService
):
@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan(useDefaultFilters=false) // Disable component scanner
public class WebServer {
// Case insensitive: could also use: http://accounts-service
public static final String ACCOUNTS_SERVICE_URL
= "http://ACCOUNTS-SERVICE";
public static void main(String[] args) {
// Will configure using web-server.yml
System.setProperty("spring.config.name", "web-server");
SpringApplication.run(WebServer.class, args);
}
@LoadBalanced // Make sure to create the load-balanced template
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
/**
* Account service calls microservice internally using provided URL.
*/
@Bean
public WebAccountsService accountsService() {
return new WebAccountsService(ACCOUNTS_SERVICE_URL);
}
@Bean
public WebAccountsController accountsController() {
return new WebAccountsController
(accountsService()); // plug in account-service
}
}
A few points to note:
WebController
is a typical Spring MVC view-based controller returning HTML. The application uses Thymeleaf as the view-technology (for generating dynamic HTML)WebServer
is also a @EnableDiscoveryClient
but in this case as well as registering itself with the discovery-server (which is not necessary since it offers no services of its own) it uses Eureka to locate the account service.@Component
classes and, in this case, finds my WebAccountController
and tries to create it. However, I want to create it myself, so I disable the scanner like this @ComponentScan(useDefaultFilters=false)
.WebAccountController
is the name the service used to register itself with the discovery-server - by default this is the same as the spring.application.name
for the process which is account-service
- see account-service.yml
above. The use of upper-case is not required but it does help emphasize that ACCOUNTS-SERVICE is a logical host (that will be obtained via discovery) not an actual host.The RestTemplate
bean will be intercepted and auto-configured by Spring Cloud (due to the @LoadBalanced
annotation) to use a custom HttpRequestClient
that uses Netflix Ribbon to do the microservice lookup. Ribbon is also a load-balancer so if you have multiple instances of a service available, it picks one for you. (Neither Eureka nor Consul on their own perform load-balancing so we use Ribbon to do it instead).
Note: From the Brixton Release Train (Spring Cloud 1.1.0.RELEASE), the RestTemplate is no longer created automatically. Originally it was created for you, which caused confusion and potential conflicts (sometimes Spring can be too helpful!).
Note that this instance is qualified using @LoadBalanced
. (The annotation is itself annotated with @Qualifier
- see here for details). Thus if you have more than one RestTemplate bean, you can make sure to inject the right one, like this:
@Autowired
@LoadBalanced // Make sure to inject the load-balanced template
protected RestTemplate restTemplate;
If you look in the RibbonClientHttpRequestFactory you will see this code:
String serviceId = originalUri.getHost();
ServiceInstance instance =
loadBalancer.choose(serviceId); // loadBalancer uses Ribbon
... if instance non-null (service exists) ...
URI uri = loadBalancer.reconstructURI(instance, originalUri);
The loadBalancer
takes the logical service-name (as registered with the discovery-server) and converts it to the actual hostname of the chosen microservice.
A RestTemplate
instance is thread-safe and can be used to access any number of services in different parts of your application (for example, I might have a CustomerService
wrapping the same RestTemplate
instance accessing a customer data microservice).
Below the relevant configuration from web-server.yml
. It is used to:
# Spring Properties
spring:
application:
name: web-service
# Discovery Server Access
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
# HTTP Server
server:
port: 3333 # HTTP (Tomcat) port
A small demo of this system is at http://github.com/paulc4/microservices-demo. Clone it and either load into your favorite IDE or use maven directly. Suggestions on how to run the demo are included in the README on the project homepage.
Some notes about Spring Boot usage by these applications. If you are not familiar with Spring Boot, this explains some of the “magic”!
The Eureka dashboard (inside RegistrationServer
) is implemented using FreeMarker templates but the other two applications use Thymeleaf. To make sure each uses the right view engine, there is extra configuration in each YML file.
This is at the end of registration-server.yml
to disable Thymeleaf.
...
# Discovery Server Dashboard uses FreeMarker. Don't want Thymeleaf templates
spring:
thymeleaf:
enabled: false # Disable Thymeleaf spring:
Since both AccountService
and WebService
use thymeleaf, we also need to point each at their own templates. Here is part of account-server.yml
:
# Spring properties
spring:
application:
name: accounts-service # Service registers under this name
freemarker:
enabled: false # Ignore Eureka dashboard FreeMarker templates
thymeleaf:
cache: false # Allow Thymeleaf templates to be reloaded at runtime
prefix: classpath:/accounts-server/templates/
# Template location for this application only
...
web-server.yml
is similar but its templates are defined by
prefix: classpath:/web-server/templates/
Note the / on the end of each spring.thymeleaf.prefix
classpath - this is crucial.
The jar is compiled to automatically run io.pivotal.microservices.services.Main
when invoked from the command-line - see Main.java.
The Spring Boot option to set the start-class
can be seen in the POM:
<properties>
<!-- Stand-alone RESTFul application for testing only -->
<start-class>io.pivotal.microservices.services.Main</start-class>
</properties>
@SpringBootApplication
@EntityScan("io.pivotal.microservices.accounts")
@EnableJpaRepositories("io.pivotal.microservices.accounts")
@PropertySource("classpath:db-config.properties")
public class AccountsWebApplication {
...
}
This is the main configuration class for AccountService which is a classic Spring Boot application using Spring Data. The annotations do most of the work:
@SpringBootApplication
- defines this as a Spring Boot application. This convenient annotation combines @EnableAutoConfiguration
, @Configuration
and @ComponentScan
(which, by default, causes Spring to search the package containing this class, and its sub-packages, for components - potential Spring Beans: AccountController
and AccountRepository
) .@EntityScan("io.pivotal.microservices.accounts")
- because I am using JPA, I need to specify where the @Entity
classes are. Normally this is an option you specify in JPA’s persistence.xml
or when creating a LocalContainerEntityManagerFactoryBean
. Spring Boot will create this factory-bean for me because the spring-boot-starter-data-jpa
dependency is on the class path. So an alternative way of specifying where to find the @Entity
classes is by using@EntityScan
. This will find Account
.@EnableJpaRepositories("io.pivotal.microservices.accounts")
- look for classes extending Spring Data’s Repository
marker interface and automatically implement them using JPA - see Spring Data JPA.@PropertySource("classpath:db-config.properties")
- properties to configure my DataSource
– see db-config.properties.As mentioned above, Spring Boot applications look for either application.properties
or application.yml
to configure themselves. Since all three servers used in this application are in the same project, they would automatically use the same configuration.
To avoid that, each specifies an alternative file by setting the spring.config.name
property.
For example here is part of WebServer.java
.
public static void main(String[] args) {
// Tell server to look for web-server.properties or web-server.yml
System.setProperty("spring.config.name", "web-server");
SpringApplication.run(WebServer.class, args);
}
At runtime, the application will find and use web-server.yml
in src/main/resources
.
Spring Boot sets up INFO level logging for Spring by default. Since we need to examine the logs for evidence of our microservices working, I have raised the level to WARN to reduce the amount of logging.
To do this, the logging level would need to be specified in each of the xxxx-server.yml
configuration files. This is usually the best place to define them as logging properties cannotbe specified in property files (logging has already been initialized before @PropertySource directives are processed). There is a note on this in the Spring Boot manual, but it’s easy to miss.
Rather than duplicate the logging configuration in each YAML file, I instead opted to put it in the logback configuration file, since Spring Boot uses logback - see src/main/resources/logback.xml. All three services will share the same logback.xml
.
출처: https://spring.io/blog/2015/07/14/microservices-with-spring
Intellij 셋팅 파일 (0) | 2019.07.09 |
---|---|
REST 개념 (0) | 2019.03.21 |
메서드, 클래스 명명규칙 어떡하면 좋을까? (0) | 2017.07.04 |
이클립스 실행 인자 입력 받기 (0) | 2016.11.02 |
자바7에서 마음에 드는 다섯 가지 (0) | 2016.10.17 |
많은 개발자들이 개발 중에 종종 고민하는 "이 메서드명은 뭘로 해야 좋을까?"란 문제는 흡사 직장인들이 "오늘 점심 뭘 먹을까?"와 거의 비슷한…, 또 본의 아니게 심각한 트라우마에 빠질 수도 있는 고민 중 하나이다. 사실 어떻게 보면 별것도 아닌 고민일 수 있는데 한국인인지라 영어도 잘 모르는 상황에서 컴퓨터랑 영어로 대화를 하려니 발생하는 헤프닝일 수도 있겠다.
domain (영역, 범위, 소유지) - 단위로 표현할 수 있고 원자성을 띄는 자바빈 클래스, Enum 클래스 등이 위치한다. 다른 곳에서 VO라고 하는 것을 본적이 있는데 필자는 domain이란 이름이 더 마음에 든다.
dao (Data Access Object) - 데이터액세스 계층과 관련된 클래스와 인터페이스들이 자리한다. DB과 관련된 작업을 한다면 사용할 수 있는 패키지명이다.
service (근무, 봉사, 편익, 이용…) - 역시 웹에서 사용되는 계층 중 하나이며 대개 dao를 조합하고 트랜잭션의 경계가 설정되는 구간이기도 하다.
core (속, 중심부, 핵심…) - 어플리케이션의 핵심적인 역할을 수행하는 클래스와 인터페이스들이 자리하는 구간이다.
task (일, 과업, 과제…) - 단어와는 가장 딴판으로 사용되는 용어 중 하나이다. 자바에서 스레드와 관련된, java.lang.Runnable 클래스의 활동을 지원하는 클래스들이 위치한다.
access (접근, 진입로, 증가…) - DB 뿐만이 아니라 다른 리소스의 자원을 불러들이고 이를 자바에서 사용가능한 상태로 가공해주는 클래스들이 위치한다.
support (지지, 지원…) - 가장 잘 이해하고 사용해야 할 패키지명이며 어느 어플리케이션이든 기본적으로 하나씩은 포함되곤 한다. 스프링 프레임워크에서는 대개 구현체를 지원하는 팩토리빈 클래스라던가 객체를 다른 클래스에서 요구하는 형태로 가공해주는 역할의 클래스들이나 부모 패키지의 인터페이스들이 구현된 클래스들이 위치해 있었다.
※ 혹시 이 패키지에 대한 다른 견해가 있으면 꼭 댓글로 말해주길 바란다.
config (구성, 설정) - 다른 언어 또는 외부 자원을 자바의 형태로 파싱해주고 그 설정을 Builder와 같은 설정 구현체에 저장해주는 역할을 담당한다.
validation (확인) - 부모 패키지의 객체들을 검증하는 검사자 클래스들이 위치한다.
util (유용한, 쓸모 있는…) - 부모 패키지의 객채들에 대해 기본적인 CRUD(Create · Remove · Update · Delete)작업을 해주거나 컬렉션 프레임워크과 비슷한, 혹은 좀 더 복잡한 작업을 도와주는 도구 클래스들이 위치한다.
예) ApplicationContext
// ApplicationContext는 사실 총 6개의 각기 다른 성격의 인터페이스들을 상속받고 있으며 스프링에서 중요한 역할을 담당하는 컨텍스트의 가장 원시적인 모델이기도 하다.
ApplicationContext -▷ EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver
ConfigurableApplicationContext -▷ ApplicationContext (and LifeCycle)
AbstractApplicationContext -▷ ConfigurableApplicationContext
GenericApplicationContext -▶ AbstractApplicationContext
GenericXmlApplicatonContext -▶ GenericApplicationContext
AnnotationConfigApplicationContext -▶ GenericApplicationContext
Simple + 인터페이스명 : Simple로 시작하는 클래스명은 이 인터페이스의 가장 기본적인 구현체를 뜻한다. 간혹 인터페이스명 + Impl과 같이 사용하는 경우도 있는데 좀 더 의미를 명확하게 하기 위해 Simle이란 접두어를 사용할 것을 권장한다.
용도명 + 인터페이스명 : 기본 구현체 외에 다른 방식으로 이용된다면 용도를 접두어로 사용하는 클래스가 구현된다.
인터페이스명 + Utils : 특정 구현체를 인자로 받아 다양한 역할을 수행해주는 도움 클래스를 지칭한다.
접두어로의 사용
get… : 어떠한 리소스를 리턴하는 메서드
set… : 프로퍼티에 해당 리소스를 내장시키는 역할의 메서드
init… : 초기값이 필요하다면 초기값을 설정하고 내부에서 관련 validate를 실행하는 역할의 메서드
load… : 전달인자를 기준으로 어떠한 값을 불러와 내장시켜주거나 카운팅하는 역할의 메서드
is… : 불리언 메서드에서 사용되는 접두어이다. 용도는 get…과 같다.
has… : contains 메서드처럼 어떠한 값을 가지고 있는지 확인해준다. 다른 점이 있다면 contains는 좀 더 범위가 넓지만 has는 특정 값으로 범위가 한정되있다.
register… : 기본적으로 set과 동작하는 방식이 같지만 set은 자바빈 규약에 얽혀있기 때문에 복잡한 연산을 포함할 수 없다. 보다 지능적인 set이 요구될 때 register과 같은 접두어를 사용한다.
create… : register…는 보통 void 형태이지만 create는 전달인자를 통해 새로운 객체를 만든 뒤에 이 객체를 리턴해준다. 등록과 생성은 엄밀히 다르므로 create를 register처럼 써서는 안될 것이다.
to… : 많이 만들어두면 참 좋은 접두어 메서드이다. 해당 객체를 다른 형태의 객체로 변환해준다.
전치사로의 사용
A-By-B : B를 기준으로 A를 하겠다는 뜻
ex) getUserByName(String name) : 이름값을 통해 유저를 불러옴
A-With-B : B와 함께 A를 하겠다는 뜻
ex) registerWithGeneratedName(BeanDefinition beanDefinition) : beanDefinition으로 다른 메서드를 통해 GeneratedName 값을 불러와 함께 저장.
접미사로의 사용
…With : 무엇과 함께 있는지, indexOf와 비슷한 성격의 접미사이다.
…s : 해당 객체가 복수의 객체를 반환하는지 단일 객체를 반환하는지 구분하는 것은 매우 중요하다. 복수형으로 표현해야 하는 메서드는 반드시 복수형으로 표현하여야 한다.
REST 개념 (0) | 2019.03.21 |
---|---|
Spring Boot microservice (0) | 2019.03.05 |
이클립스 실행 인자 입력 받기 (0) | 2016.11.02 |
자바7에서 마음에 드는 다섯 가지 (0) | 2016.10.17 |
AES256 암호화시 java.security.InvalidKeyException: Illegal key size 해결 방안 (0) | 2016.09.01 |
Spring Boot microservice (0) | 2019.03.05 |
---|---|
메서드, 클래스 명명규칙 어떡하면 좋을까? (0) | 2017.07.04 |
자바7에서 마음에 드는 다섯 가지 (0) | 2016.10.17 |
AES256 암호화시 java.security.InvalidKeyException: Illegal key size 해결 방안 (0) | 2016.09.01 |
이클립스 SVN 설정 (0) | 2016.06.30 |
자바7 출시가 점점 앞으로 다가오는데, 마음에 드는 자바7의 몇 가지 특징들은 다음과 같다.
try-with-resources 이용 자원 해제 자동 처리
사실 이거 진작에 필요했던거다. 뭔가 자원을 생성하고 사용하고 해제하는 코드는 항상 다음과 같이 구조가 중복되는 코드를 작성해야 했다. finally 블록의 자원 해제 코드 정말 하는 거 없이 여러 줄 차지한다.
이게 코딩할 때 참 귀찮게 만드는 건지 알았는지 자바7에서 try-with-resources라는 특징이 추가되었다. 이건 문법 차원에서 추가된 건데, try에 자원 객체를 전달하면 finally 블록으로 종료 처리를 하지 않아도 try 코드 블록이 끝나면 자동으로 자원을 종료해주는 기능이다. 모습은 아래와 같다.
뭔가 코드 줄 수가 많이 줄어드는 것을 알 수 있다. finally 블록에 출현했던 자원 해제 코드를 작성하지 않아도 되기 때문에 코딩도 편하다. try 블록에서 사용하는 자원의 개수가 늘어나면 try-with-resources의 위력은 배가 된다. 아래는 예이다.
멀티캐치(multicatch)
예외 처리 블록도 참 코드를 길게 만들어주는 것 중의 하나였다. 어떤 메서드를 실행하면 예외가 AException, BException, CException이 발생하는데, 이 세 예외에 대해 AException과 BException은 동일한 코드를 실행하고 CException은 다른 코드를 실행한다고 하자. 만약 AException과 BException이 공통의 부모 예외 클래스가 없다면 다음과 같이 중복되는 코드를 작성해 주어야 했다.
항상 개발 서적에서 나오는 말 중의 하나는 코드 중복을 없애라는 것이다. 그런데, 애초에 언어가 저 따구로 밖에 코드를 만들 수 없도록 했기 때문에 부득이 예외 처리 부분에서 중복된 코드가 발생했었다. 그런데, 자바7 버전에서 다음과 같이 하나의 catch 블록에서 동시에 여러 예외를 묶어서 처리할 수 있도록 했다.
catch 블록에서 한번에 여러 개의 예외를 잡을 수 있다는 의미로 위 방식을 멀티캐치(multicatch)라고 하는데, 멀티캐치 덕에 주저리 주저리 길게 나열되면서 중복되는 catch 블록을 작성하지 않아도 된다.
switch-case의 문자열 지원
이것도 좀 진작에 지원해 주었으면 좋으련만, 어쨋든 switch-case에 이제 문자열을 사용할 수 있게 되었다.
fork/join을 이용한 작업 분할 실행
자바에서 분할-정복(divide-and-conquer) 방식으로 작업을 분해하고 실행하려면 직접 관련 코드를 만들어주어야 했다. 그런데, 필자 같은 경우는 멀티코어가 정착되면서 뭔가 작업을 분할해서 다중 쓰레드를 이용해서 병렬로 정복하고 싶은 싶은 욕구가 생긴다. 필자 외에도 많은 개발자들이 멀티코어를 활용하고 싶은 욕구가 있을텐데, 자바7에 분할-정복 방식을 위한 ForkJoinPool 클래스가 추가되었다. 이 클래스는 큰 작업을 작은 작업으로 나누고 각각의 분할된 작업을 병렬로 처리해주는 기능을 제공하기 때문에 멀티코어 환경에서 처리 시간을 단축할 수 있도록 하고 있다.
중요한 건 프레임워크이기 때문에 내가 밑바닥부터 만들 필요가 없다는 점이다. 그냥 제공하는 API에 맞게 코드를 만들어주면 땡이다.
ECC 암호화 기본 내장
이것도 진작 넣었더라면 더 좋았을 것을. 암호화 처리를 위해 ECC를 제공하지 않아 외부 라이브러리를 사용하는 곳이 많았는데, 이제 그럴 필요가 없어졌다. 드디어 자바가 ECC를 지원하기 시작했다.
기타
이 외에 NIO 강화, 네트워크 관련 기능 강화 등이 있다.
출처 : http://javacan.tistory.com/entry/my-interesting-java7-five-features
메서드, 클래스 명명규칙 어떡하면 좋을까? (0) | 2017.07.04 |
---|---|
이클립스 실행 인자 입력 받기 (0) | 2016.11.02 |
AES256 암호화시 java.security.InvalidKeyException: Illegal key size 해결 방안 (0) | 2016.09.01 |
이클립스 SVN 설정 (0) | 2016.06.30 |
이클립스 메모리 늘리기 (0) | 2016.06.23 |
JAVA의 기본 정책으로는 AES128 암호화 방식까지만 사용이 가능하므로
AES256 방식으로 암호화를 하게 되면 아래와 같은 Exceptioin이 발생합니다.
java.security.InvalidKeyException: Illegal key size
이를 해결하기 위한 방법은
$JAVA_HOME/jre/lib/security 에 아래의 unlimited strength crypto file을 덮어 쓰기 하시면 됩니다.
local_policy.jar US_export_policy.jar
참고로 미 통상법에 의해 자국내에서만 AES256 방식이 허용되었다고 하네요.
아래 내용 참고하시면 되겠습니다.
참고 URL : http://www.raritan.com/helpfiles/ccsg42/en/1926.htm
Check Your Browser for AES Encryption
CC-SG supports AES-128 and AES-256. If you do not know if your browser uses AES, check with the browser manufacturer.
You may also want to try navigating to the following web site using the browser whose encryption method you want to check: https://www.fortify.net/sslcheck.html. This web site will detect your browser’s encryption method and display a report. Raritan is not affiliated with this web site.
Note: Internet Explorer 6 does not support AES-128 or -256 encryption.
AES-256 Prerequisites and Supported Configurations
AES-256 encryption is supported on the following web browsers only:
Note: Internet Explorer 7 supports AES-128 or -256 encryption in Windows Vista only. It does not support any AES encryption in Windows XP.
In addition to browser support, AES-256 encryption requires the installation of Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6.
To enable the AES-256 encryption with your browser
\lib\security\
. For example, C:\Program Files\Java 1.6.0\lib\security\
.이클립스 실행 인자 입력 받기 (0) | 2016.11.02 |
---|---|
자바7에서 마음에 드는 다섯 가지 (0) | 2016.10.17 |
이클립스 SVN 설정 (0) | 2016.06.30 |
이클립스 메모리 늘리기 (0) | 2016.06.23 |
이클립스 디컴파일러(JAD) 설정하기 (0) | 2016.06.10 |