2월, 2019의 게시물 표시

[뉴스] 지구자기장 감지하는 인간 나침반..'제6의 감각' 있다

이미지
안녕하세요, 하마연구소입니다. 인간의 가진 능력 중에 대단한 능력이 있었군요. 흥미로운 기사가 있어 공유드립니다. 원문: https://news.v.daum.net/v/20190224120036309 제목: 지구자기장 감지하는 인간 나침반..'제6의 감각' 있다 언론사: 머니투데이 요약: 인간이 나침반 없이 지구의 북쪽을 찾아내는 실험결과가 보고됐다. 경북대 채권석 교수, 한경대 김수찬 교수로 이뤄진 공동연구팀이 인간에게 자기감각이 존재하며, 이때 눈이 그 역할을 한다는 것을 규명했다고 24일 밝혔다. 채 교수는 "이 연구를 통해 인간의 자기감각이 존재함과 눈이 자기감각 기관임을 규명했다"라며, "향후 심층적인 연구를 통해 자기감각과 인간 정신활동의 상호작용을 탐색할 계획"이라고 후속연구 계획을 밝혔다. 제가 북쪽을 탐지하는 능력이 있었다니... 대단한 능력입니다. 학교 운동장에서 눈감고 실험해보면... 능력 발휘 가능할까요? 만약 허허벌판에서 길을 잃는다면, 저의 감을 믿고 길을 찾아가야겠네요. 감사합니다.

[Java] 일정시간이 지나면 값이 없어지는(expiring) 맵, 캐시로 사용가능한 ExpiringMap

안녕하세요, 하마연구소입니다. 자바 프로그래밍을 하다보면 콜렉션(collection) 중에 맵(Map)을 많이 사용합니다. 동시성(synchronization) 처리를 위하여 자바는 기본적으로 thread-safe한 java.util.concurrent.ConcurrentMap 객체를 제공하며, java.util.Collections.synchronizedMap()을 이용해도 됩니다. 그리고 복합키를 이용할 수 있도록 Apache에서 MultiKeyMap 객체도 제공합니다. 보통 이 Map에 키와 값을 계속해서 put하게되면 key만 중복되지 않으면 자꾸자꾸 들어가게 됩니다. 그 제한개수야 상당하게 크지만 그만큼 메모리 사용량은 늘어나게 되겠죠. 필자도 spring-integration에서 이러한 현상을 발견하게 되었고 이를 해결하기 위하여, 일정시간이 지나면 Map에서 자동으로 제거되는 기능이 필요하였습니다. 제거된 데이터는 더이상 필요없거나 다른 방법으로 다시 복구할 수 있는 상황이었죠. 즉, 캐시와 유사한 기능을 가진 Map이 필요했습니다. 말하고 보니 유사한 기능이 아니고, 그냥 캐시라고 해야겠네요. 캐시의 여러 정책중에 time-based 정책을 적용할 수 있는 Map이 있습니다. ExpiringMap 이라는 라이브러를 찾았습니다. 2019년 2월 24일 기준, 최신버전은 0.5.9 입니다. GitHub는 다음과 같습니다. https://github.com/jhalterman/expiringmap#expiration-policies 특징은 다음과 같습니다. High performance 고성능이랍니다. 성능 테스트는 안해봤지만, 믿어야지요! Low-overhead Time-based이니깐 시간 계산을 할텐데, 연산이나 메모리 사용량이 많지 않은가 봅니다. 이것도 믿어야지요! Zero dependency 이건 진짜입니다. maven dependency가 없습니다. Thread-safe 이야~ 멀티쓰레드 환경에서 동시성 문제도 해결해줍니다. 기본 mave...

[Java] Iterable을 stream으로 처리하기

안녕하세요, 하마연구소입니다. 자바에서 Iterable 인터페이스를 구현한 객체를 스트림으로 처리하는 간단한 방법이 있습니다. StreamSupport 클래스를 사용하면 되며, 자바에 기본으로 포함되어 있습니다. 아래 소스와 같이 Iterable에서 Spliterator를 얻어서 stream 처리하면 됩니다. Iterable < String > iterable = new LinkedList <> (); Spliterator < String > spliterator = iterable.spliterator(); StreamSupport.stream(spliterator, false ) .forEach(data -> { // do something }); StreamSupport.stream()의 두번째 파라미터를 true로 주면 parallel(병렬) 스트림 처리도 가능합니다. 감사합니다.

[Spring] spring-boot 버전 1.X와 2.X에서 Page 객체를 ObjectMapper(Jackson) 사용시 차이점

안녕하세요, 하마연구소입니다. 현시점 최신 spring-boot 릴리즈 버전은 2.1.3 입니다. 특별한 사유가 없는한 새로운 프로젝트를 시작한다면 이 버전으로 셋팅하겠죠. 하지만 2~3년전에 만들어진 프로젝트는 spring-boot 버전 1.X를 사용했을 것입니다. 필자도 수년전에 개발하고 운영중인 시스템은 spring-boot 1.4.X가 적용되어 있으며, spring-data의 JPA로 DB에서 Pageable을 이용한 페이징과 정렬 처리를 하는 기능이 많습니다. 이 기능의 반환타입은 Page이며 실제 구현체는 PageImpl로 되어있습니다. 이 Page 객체를 @RestController의 응답값으로 곧바로 넘기고, ObjectMapper(Jackson)를 통하여 JSON 문자열로 변환됩니다. 최근 spring-boot 1.4.X를 2.X로 버전업하였고, 컴파일 오류도 잡고, 로컬환경 테스트도 하고, 실제 서버에서도 테스트하여 이상없이 동작하는 것을 확인하였습니다. 하지만 조금 지나서 모니터링 시스템에서 알람이 울리기 시작하였습니다. spring-boot 버전업한 어플리케이션이 아니고, 이 어플리케이션에 REST API로 호출하는 다른 어플리케이션의 알람이었습니다. 확인해보니 2.X로 올리고 나서 REST API의 응답 포멧이 변경되었고, 이를 파싱하던 중 오류가 발생하였습니다. 뭐가 바뀐것이고? 왜 바뀌었을까? 아래는 "request -> Page 생성 -> response"의 간단한 샘플입니다. 문자열 리스트를 Page 객체로 만들어서 반환하는 컨트롤러이며, 입력 Pageable은 기본값으로 id 프로퍼티(컬럼) 오름차순 정렬했다고 설정되었습니다. @RestController @RequestMapping ( "/page" ) @Slf4j public class PageController { @GetMapping ( "/string" ) public P...

[Spring] 웹어플리케이션의 Whitelabel 오류 페이지 비활성화

이미지
안녕하세요, 하마연구소입니다. 스프링으로 웹어플리케이션을 작성하면 기본적인 오류화면은 아래와 같이 "Whitelabel Error Page"가 보입니다. 이 오류화면을 없애고 싶다면 아래와 같이 application.properties 파일에 설정을 추가하면 됩니다. server.error.whitelabel.enabled = false 위 설정은 ErrorProperties.Whitelabel로 바인딩되는데, 기본값은 true 입니다. package org.springframework.boot.autoconfigure.web ; . . . public class ErrorProperties { . . . public static class Whitelabel { /** * Whether to enable the default error page displayed in browsers in case of a * server error. */ private boolean enabled = true ; public boolean isEnabled () { return this .enabled; } public void setEnabled ( boolean enabled) { this .enabled = enabled; } } } 이렇게 Whitelabel 오류 페이지를 비활성화 시키면 아래와 같이 오류페이지가 바뀐것을 볼 수 있습니다. spring-boot-starter-web 기본 WAS인 Tomcat의 오류화면이 보입니다. 더 안 이쁘고, 심지어 톰캣 버전 정보도 보입니다. 이 톰캣 오류 정보를 표시하지 않으려면 톰캣 서버 설정 파...

[Java] 클래스에 정의된 제너릭(generic) 타입의 Class를 얻는 방법

안녕하세요, 하마연구소입니다. 자바에서 클래스를 정의할 때, 제너릭(generic) 타입을 종종 사용하게 됩니다. 코딩을 하다보면 이 generic 타입이 어떤 클래스인지 알아야할 때가 있죠. 방법은 자바 리플렉션을 이용하면 됩니다. 아래와 같이 ClassUtil 클래스에 2개 메서드를 작성하였습니다. getGenericTypsClasses() 메서드는 generic 타입을 얻기위한 핵심 코드이며, 복수개로 정의된 generic 타입을 위하여 리스트로 반환합니다. getGenericTypsClass() 메서드는 원하는 위치(index)의 generic 타입을 얻기위하여 작성하였습니다. public class ClassUtil { /** * 클래스에 정의된 generic 타입의 Class를 얻는다. * @param clazz 클래스 * @return Generic 타입의 Class 리스트 */ public static List < Class <?>> getGenericTypsClasses (Class <?> clazz) { // 클래스에 정의된 generic 파라미터에서 클래스 얻기 Type [] genericTypes = ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments(); return Arrays.stream(genericTypes) .map(genericType -> { try { Class <?> genericClass = Class.forName(genericType.getTypeName()); return genericClass...