2013년 1월 21일 월요일

Java Byte code 생성을 이용하여, Reflection 대체하기

아주 유명한 iBatis 같은 것도, 처음에는 Reflection을 통해 클래스의 동적 생성,  필드 값 설정 등을 실행했다가, 성능때문에 Java Byte Code 를 동적으로 생성하게 하여, 생성된 코드를 동적으로 실행하도록 변환했던것으로 기억합니다.

.NET 에서도 Reflection 의 성능때문에 Dynamic Method 라는 기법을 이용하여 동적으로 ILCode 를 생성하고,  그것을 실행하면 기존 Reflection 보다 4~100배 이상으로 빨라집니다.

이런 좋은 기능이 있는데, 안쓰면 바보겠죠? Java로 넘어 온 후, 실제 이런 기능의 필요성을 많이 못 느낄 정도로 iBatis 나 Hibernate 만을 사용했지만, 점점 JDBC 로우 레벨로 내려가다 보니,  꼭 필요하게 되는군요...

예를들어 객체 정보를 Map 으로 표현하고, Map으로 표현된 정보를 다른 객체 정보에 설정하려고 하는 기능 ( Mapper ) 는 상당히 많이 사용되기도 합니다. Model Mapper 라는 훌륭한 라이브러리가 있지만,  모든 것을 다 제공하는 게 아니고, 변형해서 쓰고자 하는 경우가 있어, 찾아 봤습니다.

여러가지 라이브러리가 있었지만, 작고 심플한 라이브러리를 찾다가 reflectasm 이란 놈을 발견했습니다. 
소스를 보니 제가 원하는 딱 그 것이였습니다. byte code generation 을 통해 성능을 향상시킨다^^ 캬... Good 

라이브러리를 가지고, 기존 .NET 코드와 유사하게 골격을 갖춰 봤습니다.
DynamicAccessor 라고 수형정보만 제공하면, 객체의 생성,  필드 정보 조회/수정, 메소드 실행 등을 할 수 있습니다.


동적으로 특정 수형의 속성이나 메소드 실행하는 것은 환경설정이나 사용자 매크로 등을 파싱하여 실제 클래스를 수행하게 할 때 아주 유용합니다.



다음 코드는 DynamicAccessor 를 생성해주는 Factory입니다. 굳이 factory를 만든 이유는 DynamicAccessor 생성 비용이 일반 클래스의 생성 비용에 비하여 상당한 비용이 들어가므로, Cache 를 이용하여, 재활용하자는 의미가 큽니다.  Cache는 google guava의 LoadingCache 를 사용한 이유는  Cache 자체적으로 항목들을 관리할 수 있어, 코드량 및 실수가 적어지는 것이 장점입니다.


마지막으로 DynamicAccessor 를 테스트하는 코드입니다. (reflectasm 에 성능 측정 코드가 있어 굳이 만들지 않았습니다)


댓글 없음: