Spring – MyBatis integrace a něco navíc
Článek popíše možnosti integrace Spring a MyBatis frameworků a představí užitečné rozšíření – factory na automatickou registraci Mapper rozhranní implementovaných XML definicí.
Pokud chceme na projektu integrovat Spring a MyBatis frameworky, nemáme zatím k dispozici oficiální Springem podporované řešení. Spring označoval MyBatis za “moving target”, ale oznámil, že ho bude podporovat ve Spring Data projektu. MyBatis komunita zatím zahájila vlastní snahu a její implementaci integrace už jde používat. Máme tedy k dispozici:
- Nezávislou verzi vyvinutou jako odpověď na Spring JIRA issue
- Verzi připravovanou MyBatis komunitou (vychází z předchozí)
- Spring Data projekt (zatím ve vývoji)
Protože hotové řešení potřebujeme tady a teď, používáme na aktuálním projektu první zmíněnou verzi, která k naší spokojenosti funguje s MyBatisem 3.0.2 a Springem 3.0.4. Použití je disktuváno v rámci JIRA issue, XML konfigurace pro představu může vypadat takto:
<bean id="sqlSessionFactory" class="org.springframework.orm.ibatis3.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:sale-mybatis-config.xml" /> <property name="mapperLocations"> <list><value>classpath:sale/*-mapper.xml</value></list> </property> </bean> <bean id="baseDao" abstract="true" class="org.springframework.orm.ibatis3.MapperFactoryBean"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean> <bean id="saleDao" parent="baseDao"> <property name="mapperInterface" value="sale.SaledDao" /> </bean>
Něco navíc
Pokud pracujete s mnoha Dao třídami (resp. s Mappery), XML konfigurace se začne “protivně” rozrůstat o jejich definice. Nabízí se možnost označit mapper rozhranní vhodnou anotací a registraci přenechat nějaké factory, která by to zvládla sama. Cílem je použít místo abstraktního baseDao a konkrétního saleDao (a dalších) z předchozího příkladu podobnou konstrukci:
<bean class="mybatis.MyBatisDaoFactory"> <property name="basePackage" value="sale.dao"/> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
Pro označení mapper rozhranní jsme zavedli anotaci @MyBatisDao:
@MyBatisDao
public interface SaleDao {
Long create(Sale sale);
...
}
Implementace MyBatisDaoFactory je nakonec docela jednoduchá. K nalezení kandidátů na mapper použijeme classpath scanning, k registraci jejich implementací potom BeanDefinitionRegistryPostProcessor, který dovoluje přidávat do BeanFactory nové programově vytvořené instance. Samotné vytvoření instance mapperu necháme na org.springframework.orm.ibatis3.MapperFactoryBean, stejně jako v předchozím příkladu.
Klíčová metoda postProcessBeanDefinitionRegistry potom vypadá docela jednoduše.
public class MyBatisDaoFactory implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Iterable<Class> classes = ClasspathUtils.getClasses(basePackage);
for (Class clazz : classes) {
if (clazz.isAnnotationPresent(MyBatisDao.class)) {
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class).getBeanDefinition();
beanDefinition.getPropertyValues().addPropertyValue("sqlSessionFactory", sqlSessionFactory);
beanDefinition.getPropertyValues().addPropertyValue("mapperInterface", clazz.getCanonicalName());
registry.registerBeanDefinition(clazz.getName(), beanDefinition);
}
}
}
}
Pomocná třída ClasspathUtils implementuje classpath scanning podle popisu na StackOverflow. Pokud se chcete vlastní implementaci vyhnout a nevadí vám závislost na API MyBatisu, můžete využít jeho třídu ResolverUtil.
Tento příklad také ukazuje, jak obecně z anotovaných rozhranní vytvořit Spring beany, pokud se jejich implementaci tvoří dynamicky.
Shrnutí
Článek popsal stav integrace Spring a MyBatis frameworků a představil jednoduché rozšíření pro automatické vyhledání a registraci mapperů implementovaných XML definicí.
Používáte na projektu Spring a MyBatis dohromady? Jak řešíte integraci? Podělte se o své zkušenosti v diskuzi pod článkem.

Hi there Tomas. I had just now started to write a component scan for mappers. I suggested it in Springs JIRA and also added an issue on mybatis.
But googling… to my surprise I found you already did it. Would you mind if I add your BeanDefinitionRegistryPostProcessor to MyBatis project?
Thanks!
Hi Eduardo, I’ll be happy if the mapper scanning makes it to the integration project. Feel free to add the processor. If it helps, I can send you the package provided with unit tests.
Great. Thanks a lot Tomas!
Here it is
http://code.google.com/p/mybatis/source/browse/sub-projects/mybatis-spring/trunk/src/main/java/org/mybatis/spring/annotation/
With some modifications, but its more or less you code.
And yes, if you don´t mind please send me the unit test to add them also.