1. 설정 파일의 변화.

3.0부터 들어선 후 xml 파일 내에서 설정 정보의 위치가 많아 달라졌다. 하지만 의미상의 큰 변화는 없어 보인다.
There are some changes in xml confiuration structure in iBatis 3.0 but not fudamental ones from the meaning of iBatis 2.x.

iBatis 2.x Configuration file
<sqlMapConfig>
    <properties resource="..." />
    <settings> ... </settings>
    <typeAlias ..../>
    <typeAlias ..../>
    ....
    <transactionManager> .... </transactionManager>
    <sqlMap resources = "..." />
    <sqlMap resources = "..." />
    ...
</sqlMapConfig>

iBatis 3.0 Configuration file
<configuration>
    <properties> ... </properties>

    <settings>...</setting>

    <typeAliases>
        <typeAlias ../>
        <typeAlias .../>...
    </typeAliases>

    <typeHandlers>
        <typeHandler ../>
        <typeHandler ../>
    </typeHandlers>

    <objectFactory>...</objectFactory>

    <plugins>...</plugins>

    <environments>
        <environment>
            <transactioManager />
            <dataSource />
         <environment>
    </envirnments>

    <mappers>...</mappers>
</configuration>

2.x 에서는 sqlMapConfig 노드 아래에 곧바로 설정 값들을 나열했지만 3.0 에서는 각각의 설정 정보를 포함하는 상위 노드들(properties, settings, typeAliases...)을 추가하고 이 안에 구체적인 정보들을 입력하도록 변경되었다. 외관상 3.0의 형식이 가독성이 좀 더 좋은듯 하다.
In 2.x, all kind of configuration values are enumerated directly under the "<sqlMapConfig>" node, but iBatis 3.0 inserts intermediate nodes grouping the values in their context, which seems to give a little bit simple impression in appearance

특히 3.0 에서는 mappers 노드를 추가했는데 2.x에서의 sqlMap에 해당한다.
Especially element "<mappers>..</mappers>" are introduced, which plays the same role of element "<sqlMap .. />" in 2.x.

<mappers>
     <mapper resources=""/>
     <maper resources=""/>
      ....
</mappers>

3.0에서<objectFactory/> 는 2.x에서 <resultObjectFactory/> 에 대응된다.(기능, 의미 모두 동일). ibatis가 쿼리를 보내서 얻어낸 결과값들을 가지고 특정 타입의 인스턴스를 만드는데 실제 구현 코드를 보면 주어진 Class 타입에 연결된 type handler를 찾지 못할 경우에 Object Factory 에 인스턴스 생성을 의뢰하게 된다.
"<objectFactory>" node in 3.0 corresponds to <resultObjectFactory> node in 2.x in function and meaning. Response from queries sent by iBatis is used to create an instance of appropriate type, and some pieces of source code show that when it faisl to find proper type handler related a given class it try it again with calling object factory
기본 구현은 classType.newInstance(); 와 같이 리플렉션을 이용하고 있는데 필요한 경우 이곳에서 직접 인스턴스를 생성할 수 있다. 예를 들어서 Flyweight 패턴을 적용할 경우 이 지점에서 구현 내용을 삽입하면 좋을 듯 하다.
The base implementation adopts reflection such as "classtype.newInstance()", if necessary, you can make your own implementation. For example, here is the proper point in case of applying Flyweight pattern.

<plugin ../>은 3.0에서 처음 도입된걸로 보인다.(2.x 문서에서는 비슷한 기능이 없는듯) AspectJ 에서처럼 annotation을 이용해서 특정 실행 지점에 끼어드는 기능을 구현할 수 있다(고 한다).

자세한 내용은 iBATIS-3-User_Guide.pdf 문서를 참조하는게 좋을 듯.....

2. sqlMapClient vs SqlSession

2.x에서 sqlMapClient 인스턴스를 얻어내서 구체적인 호출이 이루어졌으나 3.0에서는 SqlSession을 통해서 작업이 이루어진다.



iBATIS 2.x 에서는 DAO 클래스를 별도로 작성해서 dao가 요청을 받으면 sqlMapClient를 통해서 직접 insert, qeuryForObject, queryForList, update, delete 등을 호출하는 방식이었지만..

3.0에 와서는 Dao 클래스에 해당하는 "interface" 클래스를 선언하면 iBatis가 이를 구현한 프록시 클래스를 자동으로 생성해서 2.x에서 사용자가 작성했던 DAO 클래스의 기능을 제공한다.(이 부분에 대한 코드는 확인을 못했지만 jdk에서 제공하는 프록시를 이용해서 인스턴스를 만들고 AOP 를 통해서 끼어드는게 아닌가 싶다.)

만일 다음과 같은 POJO가 있다면..

iBatis 2.x에서는 여기에 대응되는 dao 클래스를 직접 구현해야했다.

하지만 iBatis 3.0 에서는 아래와같이 인터페이스만 작성해주면 된다.

그리고 SqlSession 을 통해서 다음과 같이 접근해서 작업을 수행한다.
2.x 에서 sqlMapClient의 insert,update 등을 호출할 때 String 문자열 값으로 실제 실행할 쿼리를 식별했는데 이때문에 mapper 역할을 하는 xml 파일의 내용을 바꾸거나 할때마다 이리저리 소스 코드의 DAO 클래스들을 쫓아다니면서 문자열을 수정해주어야 하는 번거로움이 있었다.(가끔 삑싸리나면 예외가 뜨고.. -_-;)

사용자가 직접 DAO 클래스를 작성해야 했으니 문자열을 통해서 특정 xml 설정 파일을 식별하는 과정은 피할 수 없었으나 3.0에서는 이 부분을 iBatis가 직접 처리해준다.

PersonDAO 클래스의 full qualified name이 "ibatis.mapper.PersonDAO" 일 경우에 xml 맵핑을 담당하는 Person.xml 파일을 정의할 때 반드시
<mapper namespace="ibatis.mapper.PersonDAO">
    <select id="selectPerson" ....> .... </select>
</mapper>

와 같이 namespace와 full qualified name을 일치시켜주어야 한다. 처음 프로그램 실행 시 Person.xml 의 namespace 이름으로 설정 정보를 저장하고 위에서 보여준대로 SqlSession에서는 맵퍼 인터페이스인 PersonDAO.class 를 파라머터로 전달해서 프록시 클래스를 생성, 반환한다.

하지만 여전히 컴파일할 때에 에러를 찾지는 못한다.

아래는 namespace 이름을 "ibatis.mapper.PersonMappers"로 잘못쓴 경우에 session.getMapper(....); 에서 발생하는 예외 메세지이다.
org.apache.ibatis.binding.BindingException: Type interface ibatis.mapper.PersonMapper is not known to the MapperRegistry.
    at org.apache.ibatis.binding.MapperRegistry.getMapper(MapperRegistry.java:21)
    at org.apache.ibatis.session.Configuration.getMapper(Configuration.java:358)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.getMapper(DefaultSqlSession.java:160)
    at ibatis.IBatisMain.main(IBatisMain.java:55)

설정 파일에서 mapper 인터페이스가 정의된 클래스들의 위치를 입력한 후 iBatis가 처음 기동할 때 대응되는 프록시 클래스들을 미리 초기화하는 모듈을 추가한다면 좋지 않을까? 예를 들어서

<mappers>
    <mapper resource ="ibatis.mapper.PersonMapper" init="true"/>
    ....
</mappers>

와 같이 init 애트리뷰트를 true로 주면 기동 시 PersonMapper 에 접근해서 미리 프록시 인스턴스를 만들어주고 재활용하면 좀 괜찮을 듯....

이외에도 현재 출판된 문서를 보면 몇가지 추가된 새로운 기능들이 있는데 여기서 다 소개하다보면 책 한권 쓰게 될지도 모른다.

현재 Beta 10까지 와있고 배포 후포 버전까지 온 상태이니 조만간에 정식으로 나올듯 싶다.
Posted by yeori
,