본문 바로가기

Java

[Java] Proxy를 사용하여 MyBatis의 Mapper 구현해보기 -2-

우선 앞선 포스트에서 말씀드렸듯이  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를 캐스팅을 하지 않고도 사용 할 수 있도록 해보려고 합니다.