2013년 7월 30일 화요일

IntelliJ 에서 TODO 외에 것을 추가해보자.

VS.NET 에 Resharper 를 사용할 때에는 TODO 외에 BUG, HINT, NOTE 등을 추가하여, 개발 시에 주의할 점을 특별히 기록하곤 했습니다만, IntelliJ 에서는 TODO 만 되는 줄 알았네요. 우연히 다른 것 때문에 보다보니 TODO 외에도 추가할 수 있더군요.


IntelliJ Settings -> TODO

보시면 todo, fixme 가 기본적으로 제공되고, 정규식으로 comment 에서 위의 글자로 시작하면 데코레이션을 수행해 줍니다.
전 여기에 note, bug, hint 를 추가했습니다.

에디터에서 추가한 것이 어떻게 나오나 봤습니다... 짜잔~




이쁘게 나왔죠? 원하는 색상도 가능하고, 스크롤 바에 표시도 가능합니다.
제가 Note 나 Hint 를 많이 쓰고 싶었는데 이제서야 알게 되었네요.

2013년 7월 21일 일요일

MySql Master-Slave Replication 에서 JPA 사용하기

전편의 MySql Master-Slave Replication 에서 Hiberante 사용하기 에서 몇가지 개선 사항과 JPA에도 적용하기 위해 몇가지 사항을 바꿨습니다.

1. Transactional annotation 의 readOnly 가 true 일때만 point cut 하기
2. Session.connection() 이 폐기될 것이므로 doWork() 를 사용하도록 하기 입니다.

MySqlConnectionInterceptor.java

소스를 보면 point cut 에 annotation(transactional) 다음에  "if transactional.readOnly()" 를 추가하여,  @Transactional(readOnly=true) 로 지정된 메소드만 intercept 하도록 했습니다.
이렇게 하면 부가적인 인터셉트 과정을 거치지 않아서 좋겠지요.

두번째는 Hibernate Session#connection() 이 deprecated 된다고, doWork() 를 추천하더군요. 그래서 Connection을 readOnly 로 지정하는 Work와 복원하는 Work 를 구현하여 사용했습니다.

한가지 제가 아직 해결 못한게, Intercepting 하고자 하는 메소드가 Concrete class 만 가능하고, Interface는 안되는 군요... 이 것 때문에 Spring-Data-Jpa 의 JpaRepository 에 직접 @Transactional 을 할 수 없고, Business Logic 의 Service Component 에 Transactional 을 지정해 주셔야 합니다.

개인적으로 Hibernate 자체를 사용하는 것을 선호했지만, Spring-Data-Jpa 의 많은 장점을 보고, JPA 로 넘어가려고 합니다.

앞으로는 JPA 를 기준으로 개발할 거 같네요.

 ==================

 구글링을 계속 해보니, Spring 3.0 이후로는 인터페이스에 정의된 annotation 는 상속되지 않는다고 나왔네요... 쩝... 이게 자바의 규칙이라고 하네요^^

AspectJ follows Java's rule that annotations on interfaces are not inherited.

참고 :
    Aspect Oriented Programming with Spring 중에 7.8.2 Other Spring aspects for AspectJ

2013년 7월 20일 토요일

Spring-Data-Mongo 이용하기

NoSQL DB 중 범용성이 좋은 MongoDB 를 사용하려면 여러가지 방법이 있습니다

1. Hibernate-OGM for MongoDB
2. Spring-Data MongoDB 

1번은 hibernate-core, hibernate-search, hibernate-ogm 을 활용하여 검색 시스템을 만들어봐서, 이번에는  spring-data-mongodb 를 사용해보기로 했습니다.

예전에 spring-data-jpa 에서 repository 의 concrete class 를 안 만들고, 동적으로 생성해서 사용하는 방법을 보고, 와 정말 이렇게 되면 코딩량이 엄청 줄어들겠다 싶더군요...
그래서 이번에 spring-data-mongo 의 예제를 보고, 제 나름대로 다시 구성해 봤습니다.

spring-data 의 여러가지 모듈 사용법이 더 좋고, 생산성이 높다면, 앞으로는 이 것을 계속 사용하려고 합니다...

우선 spring-data-mongo 를 사용하기 위해  dependency에 다음을 추가합니다.

pom.xml


다음으로 도메인 모델로 Album class 를 정의합니다.

Album.java
@Document 는 org.springframework.data.mongodb.core.mapping.Document 입니다.
이 어노테이션이 정의되면, MongoDB 의 Document 로 선언한 것입니다.

다음은 Album용 Repository를 정의합니다.

AlbumRepository.java


테스트용 환경 설정은 다음과 같이 합니다.
MongoConfiguration.java

주의할 점은 Repository 들을 실제 구현한 것이 아니라, Spring 이 동적으로 구현할 수 있도록 @EnableMongoRepositories 를 선언해 줘야 한다는 것입니다.

마지막으로 테스트 코드는 다음과 같습니다.

AlbumRepositoryIntegrationTest.java

를 구현하면 됩니다.
나머지 코드는  Spring-Data Mongo 의 예제에 있습니다. 그 예제는 xml 로 환경설정을 하고, 몇가지 제가 필요없는 코드를 제거했습니다.

시간나면 github에 따로 분리해서 올리도록 해보겠습니다...


Infinispan 캐시 저장소로 MongoDB 사용하기

분산캐시로 JBoss 에서 제작한 Infinispan 은 메모리 캐시로만 알고 있었는데, 여러가지 Cache Store 를 이미 제공하고 있더군요. 특히 Lucene 용이라던지, Jdbc 라던지...

Infinispan 5.3 부터는 MongoDB 를 캐시 저장소로 사용이 가능하더군요. 캐시 중에 영구 저장소에 저장해야 할 경우이면서, 빠른 PUT 성능이 필요로 하는 곳에 쓰면 좋을 것 같습니다.

우선 저는 Infinispan을 Hibernate 2nd cache 로 사용하기도 하는데요, RDBMS 보다야 캐시가 빠르지만, 보통은 휘발성이라 중간 접점이 있으면 좋겠다 싶었는데, Infinispan이 저장소로 NoSQL 을 사용할 수 있다면, 더 좋겠다 싶더군요.

제가 보통 이런 것의 사용처로는 통계성 데이터의 백데이터를 하루나 일주일 정도 캐시에 남겨 놓는 것입니다. 메모리가 제한적이니, NoSQL 에 저장했다가 거기서 로드해서 사용하고, RDBMS 는 처음 읽기만 하고 더 이상 접근하지 않는다면 좋겠다 싶어서지요.

그럼 Infinispan 과 MongoDB 를 활용해서 캐시를 사용해 보도록 하겠습니다.


우선 infinispan-core, infinispan-cachestore-mongodb 를 maven dependency 에 추가합니다. 현재 가장
최신 버전은 5.3.0.Final 입니다.

코드는 Infinispan을 사용하는 것과 같고, 다만 CacheStore를 설정해주는 부분만 새로 추가하면 됩니다.
여기서는 ConfigurationBuilder 를 이용하여 MongoDB CacheStore 설정을 수행했습니다.

MongoDbAsCaceStoreTest.java

보안을 위해서 username, password 도 설정이 가능합니다.
좀 더 자세한 내용은 Infinispan CacheStore  를 참고하세요.

참 MongoDB 에 접속하기 위해 Java 용 Driver 도 dependency에 추가해 주세요.

2013년 7월 9일 화요일

IntelliJ 12 + lombok project plugin 이 동작하지 않을때...

IntelliJ 12용 lombok plugin 0.6.2 가 릴리즈되어 기쁜 마음으로 Upgrade 했습니다.
아니 근데.. 잘 되던 @Getter, @Setter 가 잘 안되네요...
쩝 뭐가 꼬였나... maven repository도 삭제해보고, pom 파일도 다시 import 해보고 테스트 해보니 maven으로는 제대로 작동하는데 IntelliJ 자체에서 작업 시 예외가 발생하더군요...

plugin 문제인가 싶어, rollback 하려다가 setting 창에 요런 게 새로 생겼네요 (그 전에도 있었나 모르겠지만, 전 지금 처음 알았습니다.)




아니 뻘건 줄로 뭔 말을 썼는데... external compiler option? annotation processors? 을 활성화 시키라구? external compiler option 은 scala 에서만 쓰는 줄 알았는데? annotation processor 는 lombok 에서 필요한 기능인 줄 알겠는데... 저게 어디 있는건데?...  창에서 검색할 수 있으니 좋네요^^ 


요 화면과 같이 Compiler 내에 Annotation Processors 라는 항목이 있군요. 창 최상단에 있는 Enable annotation processing 항목을 check 해주고, 제일 아래의 "Apply" 버튼을 누른 후, lombok plugin 설정 창으로 가보면


다음과 같이 바뀌어 있을 겁니다. 아니면 Verify xxxx 버튼을 누르면 lombok 을 제대로 사용할 수 있는지 다시 평가해 줍니다.

흠 버전 업하면서, 옵션으로 변경되었나 봅니다.
요것때문에 한 시간을 허비했네 쩝...





2013년 7월 8일 월요일

Scala 와 Java 의 자료구조 변환 문제를 쉽게 해결합시다.

Scala의 장점 중에 하나가 상당히 다양하고, 강력한 자료구조 및 편의성을 제공하는 것입니다. 특히 자료구조를 병렬로 처리하는 것도 아주 쉽게 적용할 수 있습니다.
이런 Scala의 장점을 Java에서 사용하기 위해서 단순한 작업 두 가지만 해주면, Scala 의 강력한 자료구조를 쉽게 사용할 수 있습니다.

첫째는 maven으로 java와 scala 코드를 동시에 빌드할 수 있는 환경을 만드는 것이고,
둘째는 Java 자료구조와 Scala 자료구조를 쉽게 변환할 수 있도록 하는 것입니다.

첫째는 링크를 따라가시면 쉽게 환경을 구성할 수 있으니 생략하구요,
자료구조의 변환에 대한 코드만 보여드리겠습니다.
물론 제가 만든 게 아니라 Scala 에서 기본 제공하는 JavaConversions 라는 Object 를 사용하는 것입니다.

Java2Scala Object 를 보시면 모든 메소드가 implicit 로 정의되어 있습니다. 암묵 변환(implicit conversion) 이 되서, 개발자는 Object 를 import 하는 것으로 끝납니다.

Java2Scala.scala


java 코드에서 scala 메소드를 사용할 때, java 의 list 나 set 을 전달하면, 알아서 scala 의 ArrayBuffer 나 HashSet으로 변환하여 작업한 후 결과도 java 의 자료구조 형식으로 변환합니다.

scala 의 implicit 기능을 사용하면 엄청난 유연성이 생깁니다.


MySql Master Slave Replication 에서 Hibernate 사용하기 2

MySQL Master Slave Replication 에서 Hibernate 사용하기 에서 만든 ConnectionInterceptor 는 Custom Annotation을 사용하여, 부가적인 노가다가 필요했습니다.

보통 Spring 을 사용하니 Spring 의 @Transactional 을 이용하여, readOnly 속성에 따른 작업을 수행하면 될 것입니다.
제가 Spring Aop 에 초보라 좀 찾아보는데 시간이 걸리네요...

어쨌든 구글링을 통해 방법을 찾아서 개선된 ConnectionInterceptor 를 올립니다.

@Transactional을 사용하는 ConnectionInterceptor.java


보시다시피 @Transactional 이 정의된 메소드에 readOnly=true 인 경우에는 Slave 에 접속하게하고, 아니라면 그대로 실행하도록 합니다.

2013년 7월 6일 토요일

MySQL Replication 환경 하에서 Hibernate 사용하기

타 RDBMS 보다 MySQL이 좋은 점 중에 하나가 다중 서버 환경으로의 전환이 용이하고, 안정적이라는 점이다. 보통의 Legacy 시스템에서는 RDBMS 서버 한대를 두고, 백업 서버를 두는 방식을 택하고, 성능이 모자라면 scale up 을 수행하는데, MySQL은 Replication을 이용하여 scale out 을 수행하므로서 부하 분산으로 성능을 높히는 방식입니다.



Hibernate의 경우 SessionFactory가 RDBMS 와 1:1 매핑이 되는 관계라 위와 같이 멀티 서버의 경우에는 중간에 Proxy 서버를 두던가,  MySQL Replication Driver 를 이용해야 합니다.
Proxy 서버를 둔다는 것은 Clustering 을 구성하는 것과 같으니 Proxy 서버 주소만 알면 되지만, Replication Driver를 사용 시에는 Master / Slave 서버별로 작업의 특성에 따라 구분해 줘야 합니다.

즉 Master 서버는 Read/Write를 할 수 있지만, Slave 서버는 Read 작업만 수행해야 합니다. 이렇게 하려면 작업 전에 Connection 의 isReadOnly 속성을 변경하여, 원하는 종류의 서버를 선택하게끔 해야 합니다.

이를 위해 Spring AOP 를 이용하여, 작업 시작 전에 작업 종류에 따라 Connection 속성을 변경하는 interceptor 를 제작합니다.

ConnectionInterceptor.java

line 11 에 있는 @Arount 를 보시면,  ReadOnlyConnection 이라는 annotation 이 있는 메소드를 intercept 하도록 합니다.  이 메소드는 readonly 작업을 뜻하므로 connection의 readonly 값을 true 로 하여, MySQL 의 Slave 서버에 접속하도록합니다.

ReadOnlyConnection annotation은 메소드에만 적용되도록 합니다.

ReadOnlyConnection.java

자 이제 테스트를 위한 서비스를 제작해 봅시다.

SimpleEntityServiceImpl.java
서비스 클래스에서 조회 메소드에서 @ReadOnlyConnection 을 사용하므로서 AOP 를 통해 ConnectionInterceptor 를 통해, Slave 서버에 접속하도록 했습니다.

이를 통해 Master/Slave 를 구분하고,  여러대의 Slave 도 Replication Driver 가 RoundRobin 방식으로  서버를 지정해주니, Application 개발자는 RDBMS 환경에 크게 신경 쓰지 않고, 자신의 분야에만 집중 할 수 있게 될 겁니다^^

또 한가지 SessionFactory가 하나로 유지되므로, 2nd Cache 도 하나가 되므로, 성능상의 잇점과 Cache와의 불일치에 대해 다른 방식보다 어느 정도 잇점이 있을 것입니다