Contexte technique
Un projet web utilisant Spring MVC et MyBatis intègre les paramètres de connexion JDBC dans un fichier externe via <context:property-placeholder>. La configuration suivante est utilisée pour initialiser le scanner de mappers :
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="packageBase" value="org.chench.test.springmvc.dao" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Lors de l'initialisation, une erreur de type NumberFormatException survient avec la valeur ${master.acquireIncrement}. Le problème provient de l'incapacité à résoudre les variables de configuration externes.
Solution recommadnée
Il est nécessaire de remplacer la propriété sessionFactory par sessionFactoryBeanName :
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="packageBase" value="org.chench.test.springmvc.dao" />
<property name="sessionFactoryBeanName" value="sessionFactory" />
</bean>
Analyse technique
Cette erreur est liée à un problème historique dans les versions anciennes de MyBatis (voir https://github.com/mybatis/old-google-code-issues/issues/414). La méthode setSqlSessionFactory() a été dépréciée au profit de setSqlSessionFactoryBeanName().
Le composant MapperScannerConfigurer implémente BeanDefinitionRegistryPostProcessor qui permet à Spring de gérer automatiquement les dépenadnces :
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
// Injection automatique par Spring
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
// Utilisation du nom du bean plutôt que la référence
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
}