mybatis mapper生成流程

mybatis提供了一种非常简便的方式去访问数据库,定义接口和sql之后,就能自动帮你完成jdbc操作。这得益于它的mapper机制,本篇文章在于分析mapper的流程。

一、生成MapperProxyFactory对象

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

从mybatis的官方示例代码可以看到,mapper接口的加载是通过Configuration类的addMapper方法去实现的。

public <T> void addMapper(Class<T> type) {
    this.knownMappers.put(type, new MapperProxyFactory(type));
    MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
    parser.parse();
}

可以看到,这里创建了一个MapperProxyFactory对象,当用户调用getMapper方法时,则会调用该factory生成一个基于jdk的代理

public T newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

最终调用方法时,则是通过MapperProxy的invoke方法完成逻辑调用。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  final MapperMethod mapperMethod = cachedMapperMethod(method);
  return mapperMethod.execute(sqlSession, args);
}

MapperProxy内部由MapperMethod的execute完成方法调用,该方法调用sqlSession完成操作,即完成了mapper的封装。

if (SqlCommandType.INSERT == command.getType()) {
  Object param = method.convertArgsToSqlCommandParam(args);
  result = rowCountResult(sqlSession.insert(command.getName(), param));
...

二、通过mapperProxyFactory生成Mapper接口的代理对象

mybatis提供了一个MapperProxyFactory类,通过调用该类的工厂方法newInstance就可以生成目标mapper接口的代理对象。但是想使用spring自动注入的功能,还需要针对每个mapper接口创建一个FactoryBean添加到spring的factory中。回忆一下我们使用mybatis自动为mapper生成代理的使用方法:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="orj.worf.mybatis.mapper"/>
    <property name="annotationClass" value="org.springframework.stereotype.Repository"/>
</bean>

通过MapperScannerConfigurer配置了要扫描的包,以及一些注解过滤器(选配),来为mapper接口生成对应的factoryBean,这个类实现了BeanDefinitionRegistryPostProcessor,在spring容器启动的时候,该类扫描到符合条件的mapper接口,生成对应的FactoryBean:MapperFactoryBean。详细的流程如下:


mapper初始化.jpg

之后将mapper注入到对应的业务类时,spring会调用FactoryBean的getObject方法,该方法利用MapperProxyFactory生成mapper的代理对象,。

public T getObject() throws Exception {
  return getSqlSession().getMapper(this.mapperInterface);
}

...
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
return mapperProxyFactory.newInstance(sqlSession);

三、MapperProxyFactory的生成策略

第一小节中我们了解到了调用Configuration的getMapper方法来为mapper接口生成代理工厂对象MapperProxyFactory这一硬编码方式。在实际使用mybatis mapper时,它是怎么自动化给每个mapper调用getMapper方法的呢?这一切要从SqlSessionFactoryBean上得到答案。


SQLSessionFactoryBean.jpg

SqlSessionFactoryBean的afterPropertiesSet扫描mapperLocations下所有的xml映射,最后把xml中mapper标签定义的namespace即mapper接口,利用Configuration的getMapper方法为期生成MapperProxyFactory对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容