org.mybatis.spring.mapper.MapperFactoryBean
是我们本篇文章需要研究到核心类。这个类的源码在mybatis-spring.jar中,不在mybatis.jar中
比如我们数据库操作到interface为 GreetMapper
public interface GreetMapper {
String list();
}
MapperFactoryBean会生成一个GreetMapper到代理对象. 这个对象是实现了GreetMapper接口的。
我们下面来看看MapperFactoryBean.java
package org.mybatis.spring.mapper;
import static org.springframework.util.Assert.notNull;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.FactoryBean;
/**
* BeanFactory that enables injection of MyBatis mapper interfaces. It can be set up with a SqlSessionFactory or a
* pre-configured SqlSessionTemplate.
* <p>
* Sample configuration:
*
* <pre class="code">
* {@code
* <bean id="baseMapper" class="org.mybatis.spring.mapper.MapperFactoryBean" abstract="true" lazy-init="true">
* <property name="sqlSessionFactory" ref="sqlSessionFactory" />
* </bean>
*
* <bean id="oneMapper" parent="baseMapper">
* <property name="mapperInterface" value="my.package.MyMapperInterface" />
* </bean>
*
* <bean id="anotherMapper" parent="baseMapper">
* <property name="mapperInterface" value="my.package.MyAnotherMapperInterface" />
* </bean>
* }
* </pre>
* <p>
* Note that this factory can only inject <em>interfaces</em>, not concrete classes.
*
* @author Eduardo Macarron
*
* @see SqlSessionTemplate
*/
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
private boolean addToConfig = true;
public MapperFactoryBean() {
// intentionally empty
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
/**
* {@inheritDoc}
*/
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
try {
configuration.addMapper(this.mapperInterface);
} catch (Exception e) {
logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
throw new IllegalArgumentException(e);
} finally {
ErrorContext.instance().reset();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
/**
* {@inheritDoc}
*/
@Override
public Class<T> getObjectType() {
return this.mapperInterface;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSingleton() {
return true;
}
// ------------- mutators --------------
/**
* Sets the mapper interface of the MyBatis mapper
*
* @param mapperInterface
* class of the interface
*/
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
/**
* Return the mapper interface of the MyBatis mapper
*
* @return class of the interface
*/
public Class<T> getMapperInterface() {
return mapperInterface;
}
/**
* If addToConfig is false the mapper will not be added to MyBatis. This means it must have been included in
* mybatis-config.xml.
* <p>
* If it is true, the mapper will be added to MyBatis in the case it is not already registered.
* <p>
* By default addToConfig is true.
*
* @param addToConfig
* a flag that whether add mapper to MyBatis or not
*/
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
/**
* Return the flag for addition into MyBatis config.
*
* @return true if the mapper will be added to MyBatis in the case it is not already registered.
*/
public boolean isAddToConfig() {
return addToConfig;
}
}
主要看getObject() 和isSingleton()
isSingleton()返回true说明这个getObject只会被调用一次。
getObject()
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
查看getMapper() 选择实现类是SqlSessionTemplate
SqlSessionTemplate#getMapper()
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
继续查看getMapper的定义 Configuration.java
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
这时候可以定位到MapperRegistry.java中到getMapper(type, sqlSession)的定义
而里面又会调用mapperProxyFactory.newInstance(sqlSession);
org.apache.ibatis.binding.MapperProxyFactory#newInstance()
//Step 1
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
//Step 2
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
Proxy.newProxyInstance() 说明开始创建代理对象。 注意这里涉及到InvocationHandler接口的实现类MapperProxy
这个代理对象最终成为MapperFactoryBean.getBean()到返回值,并且被单例形式注册到Spring容器。
当我们使用
@Autowired
private GreetMapper greetMapper;
public void greet() {
List list = greetMapper.list();
}
greetMapper.list()执行的时候。 就会执行InvocationHandler接口的实现类MapperProxy里到invoke方法。 整个JDK动态代理过程就完成了。
在invoke方法里,会根据事先解析好到sql语句进行数据库操作,并返回数据库操作结果.
连载列表
MyBatis源码解析1-全局熟悉源码