Injecting Mappers
Rather than code data access objects (DAOs) manually using SqlSessionDaoSupport or SqlSessionTemplate, Mybatis-Spring provides a proxy factory: MapperFactoryBean. This class lets you inject data mapper interfaces directly into other beans. When using mappers you simply call them as you have always called your DAOs, but you won't need to code any DAO implementation because MyBatis-Spring will create a proxy for you.
With injected mappers your code will have no direct dependencies on MyBatis, Spring or MyBatis-Spring. The proxy that MapperFactoryBean creates handles opening and closing the session as well as translating any exceptions into Spring DataAccessExceptions. In addition, the proxy will start a new Spring transaction if required or participate in an existing one if it a transaction is active.
MapperFactoryBean
A data mapper is added to Spring like the following:
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
MapperFactoryBean creates a proxy class that implements UserMapper and injects it into the application. Because a proxy is created at runtime, the specified Mapper must be an interface, not an implementation class.
If the UserMapper has a corresponding MyBatis XML mapper file, it will be parsed automatically by the MapperFactoryBean if the XML file is in the same classpath location as the mapper interface. There is no need to specify the mapper in a MyBatis configuration file unless the mapper XML files are in a different classpath location. See the SqlSessionFactoryBean's configLocation property for more information.
Note that MapperFactoryBean requires either an SqlSessionFactory or an SqlSessionTemplate. These can be set through the respective sqlSessionFactory and sqlSessionTemplate properties, or they can be autowired by Spring. If both properties are set, the SqlSessionFactory is ignored. Since the SqlSessionTemplate is required to have a session factory set, that factory will be used by MapperFactoryBean.
You can inject mappers directly on your business/service objects in the same way you inject any other Spring bean:
<bean id="fooService" class="org.mybatis.spring.sample.mapper.FooServiceImpl"> <property name="userMapper" ref="userMapper" /> </bean>
This bean can be used directly in application logic:
public class FooServiceImpl implements FooService {
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
public User doSomeBusinessStuff(String userId) {
return this.userMapper.getUser(userId);
}
}Notice that there are no SqlSession or MyBatis references in this code. Nor is there any need to create, open or close the session, MyBatis-Spring will take care of that.
MapperScannerConfigurer
There is no need to register all your mappers in the Spring XML file. Instead, you can use a MapperScannerConfigurer that will search the classpath for your mappers and set them up automatically as MapperFactoryBeans.
To set up a MapperScannerConfigurer add the following to the Spring configuration:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="org.mybatis.spring.sample.mapper" /> </bean>
The basePackage property lets you set the base package for your mapper interface files. You can set more than one package by using a semicolon or comma as a separator. Mappers will be searched for recursively starting in the specified package(s).
Notice that there is no need to specify a SqlSessionFactory or SqlSessionTemplate because the MapperScannerConfigurer will create MapperFactoryBeans that can be autowired. But if you are using more than one DataSource autowire may not work for you. In this case you can use the sqlSessionFactoryBeanName or sqlSessionTemplateBeanName properties to set the right bean name to use. Note that bean names are required, not bean references, thus the value attribute is used instead of the usual ref:
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
NOTE sqlSessionFactoryBean and sqlSessionTemplateBean properties were the only option available up to MyBatis-Spring 1.0.2 but given that the MapperScannerConfigurer runs earlier in the startup process that PropertyPlaceholderConfigurer there were frequent errors. For that purpose that properties have been deprecated and the new properties sqlSessionFactoryBeanName and sqlSessionTemplateBeanName are recommended.
MapperScannerConfigurer supports filtering the mappers created by either specifying a marker interface or an annotation. The annotationClass property specifies an annotation to search for. The markerInterface property specifies a parent interface to search for. If both properties are specified, mappers are added for interfaces that match either criteria. By default, these two properties are null, so all interfaces in the given base package(s) will be loaded as mappers.
Discovered mappers will be named using Spring default naming strategy for autodetected components (see section 3.14.4 of the Spring manual). That is, if no annotation is found, it will use the uncapitalized non-qualified class name of the mapper. But if either a @Component or a JSR-330 @Named annotation is found it will get the name from the annotation. Notice that you can set the annotationClass property to org.springframework.stereotype.Component, javax.inject.Named (if you have JSE 6) or to your own annotation (that must be itself annotated) so the annotation will work both as a marker and as a name provider.