이전 글에서 Mapper를 MapperFactory라는 클래스를 통해 생성하여
구현하였었습니다.

앞에서도 말씀드렸지만
이전 예제는 Mapper의 return type이 고정되어 버린다는
단점이 있었습니다. 이 부분을 Generic을 사용하여 수정해보려고 합니다.

기본적으로 앞서 구현했던 Select 어노테이션과 User클래스, 그리고 User를 Select 할 수 있는 UserMapper외에 
Depart 도메인에 대한 Mapper를 추가하겠습니다.

  Depart.java
DepartDataMapper.java

Depart와 Depart를 Select하는 Mapper입니다.

그 다음 이 Mapper를 대신하여 수행 될 ProxyHandler입니다.


MapperProxyHandler.java

보시면 아시겠지만
리턴되어야하는 타입이 User와 Depart 두개로
이를 구분하기 위하여 내부적으로 If문을 사용하고 있습니다.

지금은 Type이 2개뿐이지만 실제로는 이런식으로는 구현 자체가 어려울 것 입니다.
이 부분은 Reflect를 사용하여 IF문을 쓰지 않고도 Return Type을 구분 하도록 할 수도 있습니다.



MapperProxyHandler.java (개량형)

* 위 예제는 풍주형님(http://pungjoo.tistory.com/)께서 댓글로 알려주신 내용입니다. 

위에 보시면 메서드명을 인위적으로 만들어서 setter 메서드를 relfect로 실행하여
값을 셋팅하고 있습니다.

위 예제에서 메서드명을 DB ResultSet의 MetaData로부터 컬럼명을 읽어서
만들어 낼 수도 있고, 스프링프레임워크등을 사용하면 BeanProperty와 같은 라이브러리를
사용하여 좀 더 쉽게 사용 할 수도 있습니다.

아무튼 위와 같이 ProxyHandler가 작성되고나면 이제 MapperFactory를 작성해야 합니다.


MapperFactory.java
이렇게 Generic을 사용하면 이 Factory가 여러 종류의 Mapper를 생성 할 수 있게 됩니다.
아래 예제처럼요..


Test.java

이제 MapperFactory는 더 이상 Mapper의 Type에 종속적이지 않습니다.
보시면 하나의 Factory에서 여러 종류의 Mapper를 만들어내고 있습니다.

이렇게해서 mybatis에서 사용되는 mapper를 proxy api를 활용하여
구현해보았습니다.당연히 실제 Mybatis 내부적으로는 훨씬 많은 validation로직과 기타 예외에 대한 처리들이
구현되어 있을 것 입니다.

단순히 흉내내기에 불과하지만
proxy, annotation, generic등 여러 종류의 api에 대해서도
한번 훑어 볼 수 있는 예제라고 생각합니다.


Posted by 용식
TAG mybatis, proxy
우선 앞선 포스트에서 말씀드렸듯이  http://pungjoo.tistory.com/17  이곳에서
Proxy API의 사용방법과 내용에 대해서 먼저 읽어주세요.

위 내용을 기반으로 예제가 작성됩니다.

myBatis에서 사용하는 Mapper를 한번 비슷하게 구현해보겠습니다.

우선 Mapper에서 쿼리문을 지정하기 위해 사용될 Annotation을 만들어야 합니다.
실제 MyBatis와 동일하게 Select라는 이름을 사용하겠습니다.

  Select.java

RetentionPolicy가 RUNTIME으로 되어 있으므로, 이 Annotation은 JVM이 실행되는 동안 사용가능하게 됩니다.
그리고 query라는 변수를 통해 위 Annotation은 쿼리식을 가지고 있을 수 있게 됩니다.

그 다음 필요한 클래스는 Domain의 역할을 할 User 클래스입니다.
간단하게 이름과 주소 필드만을 가지고 있습니다.
이 예제에서는 실제로 DB와 연결하여 데이터를 가져 올 것이 아니고
구현되는 형태만을 보기 위함이기 때문에 실제 데이터가 이 Domain에 들어가지는 않을 것 입니다.


User.java

이번에는 Mapper입니다. Mapper는 인터페이스이며 메서드에는 해당 메서드가 호출 될 때 실행 될
쿼리문이 설정되어 있습니다.


UserDataMapper.java

그리고 위 Mapper는 ProxyHandler를 사용하여 Proxy Instance로 사용되고 이를 통해
위 Mapper의 selectUser 메서드를 실행하면 User 클래스에 데이터가
담겨 return됩니다. 구현 클래스도 없는데말이죠. 그러면 실제로 그 일을 하게 될 ProxyHandler를 
살펴보겠습니다.



MapperProxyHandler.java

앞선 예제들과 마찬가지로 InvocationHandler를 구현하고 있습니다.
Proxy API에 의해서 위 Mapper의 getUser 메서드가 호출 될 경우 이 MapperProxyHandler의 invoke 메서드가
실행됩니다. 

이 메서드의 파라메터 중 Method 파라메터로 getUser가 넘어오게 되고 이 메서드로부터 Select Annotation을
얻어낼 수 있습니다. 그리고 그 Select Annotation으로부터 쿼리를 받아 실행을 하는 로직이 이 invoke 메서드안에
구현되게 됩니다.

위 Handler를 통해 메서드를 실행하게 하려면 Proxy.newProxyInstance 메서드를 사용해야합니다.

이 부분을 MapperFactory라는 이름으로 해당 Mapper를 가져 올 수 있도록 하겠습니다.


MapperFactory.java

그리고 최종적인 실행되는 모양은 아래와 같습니다.


Test.java

MapperFactory를 통해 UserDataMapper를 얻어내고
이 때 내부적으로는 Proxy를 사용 할 준비를 합니다. 그리고 selectUser 메서드를 실행 할 때 위에 작성된
invoke 메서드를 실행하게 됩니다.

이 예제에서는 한가지 (사실은 매우 여러가지...) 단점이 있는데요
MapperFactory가 한번에 하나의 Mapper만 return 할 수 있다는 것 입니다. 예를 들어 부서를 Select하는
Mapper가 있다면 리턴되는 Domain의 Type이 User가 아니게 되고, 따라서 Mapper도 바뀌어야 한다는
것 입니다.

물론 캐스팅을 사용하면 여러 Mapper를 사용하도록 할 수도 있습니다. 

이 다음 포스트에서는 위 MapperFactory를 제네릭을 사용하여
범용적으로 여러 Mapper를 캐스팅을 하지 않고도 사용 할 수 있도록 해보려고 합니다.
Posted by 용식
TAG mybatis, proxy
얼마전에 Ibatis 3.0에 해당되는 mybatis가 나왔었습니다.
xml에 쿼리를 작성하지 않고도 어노테이션과 인터페이스만으로 쿼리를 실행하고 결과를 받을 수 있게 기능이
추가 되었는데요

대략적인 API의 사용 예를 보면 아래와 같습니다.

  MyBatis에서 Mapper의 사용예제
UserDataMapper.java 위와 같이 Mapper 인터페이스에 어노테이션을 활용하여 쿼리문을 넣어 놓으면
별도의 구현클래스를 만들지 않아도, SqlSession으로부터 Mapper를 얻어와서 

바로 쿼리를 실행하고 그에 따른 결과를 받을 수 있게 되어있습니다. 물론 SqlSession에는 MyBatis에서 사용하기 위해서 기본적은 DB 관련 정보들을 properties로부터 읽어와서 사용하도록 되어있을 것 입니다. 어떻게 아무런 구현체도 없이 저렇게 사용이 가능 할 것일까요? 먼저 아래의 포스트를 읽어주세요. 


http://pungjoo.tistory.com/17


GS에서 근무 할 때 저에게 많은 것을 가르쳐주셨던 풍주형님의 글입니다. 여전히 제목에는 작성중이라고 되어있지만 이 글은 저 상태만으로도 Proxy에 대해서 간단한 예제를 통해 많은 것을 보여주는 글입니다. 이 글을 보고 이해가 잘 되지 않는 예제를 몇 번씩 실행해보고 고쳐보면서 내용을 익혔었는데 MyBatis의 Mapper를 보고 MyBatis에서 Proxy를 사용하는 것이 아닐까? 라는 생각이 들었었습니다. Mapper에는 쿼리와 Return Type만이 선언 되어있습니다. 아무런 구현체가 없습니다. 그렇다면 이 Mapper의 역할을 다른 클래스가 대신 하도록 되어 있는 것이 아닐까 라는 생각과 풍주형님께서 작성하셨던 글의 예제를 좀 활용하면 비슷하게 구현을 해 볼 수 있게다 싶었던거죠.. ㅎㅎ 앞으로 2개의 포스트를 거쳐서 Proxy를 사용하여 MyBatis의 Mapper를 흉내내보려고 합니다. 본래 팀내 후배들에게 가르쳐주려고 만들었던 예제들인데요 그 예제들에 대해서 설명을 하는 형태로 글을 작성하려 합니다. 


Posted by 용식
TAG mybatis, proxy