MyBatis - DAO接口不需要实现类分析(下)

简介: MyBatis - DAO接口不需要实现类分析(下)

(2)spring+mybatis注解方式是怎样在没有实现类的dao接口的情况下结合

先看一下spring是怎么管理mybatis的dao接口


image.png


配置文件扫描所有mybatis的dao接口:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
   <property name="basePackage" value="com.mybatis.demo.*.mapper" />  
   <!-- 这里要用传beanName,不能传bean的ref,否则,会提前加载,用不到PropertyPlaceholder,切记 -->  
   <property name="sqlSessionFactoryBeanName" value="demo_sqlSessionFactory" />  
</bean> 

ClasspathMapperScanner.doScan

/** 
  * Calls the parent search that will search and register all the candidates. 
  * Then the registered objects are post processed to set them as 
  * MapperFactoryBeans 
  */  
  @Override  
  public Set<BeanDefinitionHolder> doScan(String... basePackages) {  
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);  
    if (beanDefinitions.isEmpty()) {  
      logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");  
    } else {  
      for (BeanDefinitionHolder holder : beanDefinitions) {  
        GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();  
        if (logger.isDebugEnabled()) {  
          logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()   
              + "' and '" + definition.getBeanClassName() + "' mapperInterface");  
        }  
        // the mapper interface is the original class of the bean  
        // but, the actual class of the bean is MapperFactoryBean  
        definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());  
        definition.setBeanClass(MapperFactoryBean.class);</span>  
        definition.getPropertyValues().add("addToConfig", this.addToConfig);  
        boolean explicitFactoryUsed = false;  
        if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {  
          definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));  
          explicitFactoryUsed = true;  
        } else if (this.sqlSessionFactory != null) {  
          definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);  
          explicitFactoryUsed = true;  
        }  
        if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {  
          if (explicitFactoryUsed) {  
            logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");  
          }  
          definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));  
          explicitFactoryUsed = true;  
        } else if (this.sqlSessionTemplate != null) {  
          if (explicitFactoryUsed) {  
            logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");  
          }  
          definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);  
          explicitFactoryUsed = true;  
        }  
        if (!explicitFactoryUsed) {  
          if (logger.isDebugEnabled()) {  
            logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");  
          }  
          definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);  
        }  
      }  
    }  
    return beanDefinitions;  
  }

意思就是对于mybatis的dao接口,spring是以MapperFactoryBean的方式来管理的,举个例子说:

@autowired
private UserMapper userMapper;

这个userMapper返回的实例对象会是MapperFactoryBean,这个过程是由spring控制的,因为笔者对于spring原理没有深入研究过,笔者在这里不做说明。

可能大家好奇,为什么这里不能直接像第一部分一样,通过sqlsession.getMapper(...)的方式来获取dao接口对象呢,笔者在这里觉得,之所以出现MapperFactoryBean

这个中间对象,是因为SqlSessionTemplate,sqlsessionTemplate是mybatis-spring封装的用于方法执行mybatis方法的工具类,但是大家平时可能很少用到这个。

笔者在这里做了一个小测试利用,简单的看一下它的用法

/** 
 * 类SqlTemplateTest.java的实现描述:TODO 类实现描述  
 * @author yuezhihua 2015年7月29日 下午2:07:44 
 */  
@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {  
        "classpath*:spring/demo-locator.xml"  
})  
public class SqlTemplateTest {  
    @Autowired  
    private SqlSessionTemplate sqlSessionTemplate;  
    @Autowired  
    private SqlSessionFactory sqlSessionFactory;  
    /** 
     * 初始化datasource 
     */  
    @Before  
    public void init(){  
        DataSource ds = null;  
        try {  
            ds = BaseDataTest.createUnpooledDataSource(BaseDataTest.DERBY_PROPERTIES);  
            BaseDataTest.runScript(ds, "com/mybatis/demo/databases/lazyloader/lazyloader-schema.sql");  
            BaseDataTest.runScript(ds, "com/mybatis/demo/databases/lazyloader/lazyloader-dataload.sql");  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
    }                 
    /** 
     * mybatis-spring : sqlSessionTemplate测试查询 
     * java.lang.UnsupportedOperationException: Manual close is not allowed over a Spring managed SqlSession不要在意 
     */  
    @Test  
    public void testSelect(){  
        UserPO  result = sqlSessionTemplate.selectOne("com.mybatis.demo.lazyload.mapper.UserMapper.getUserByUsername", "zhangsan");  
        System.out.println(result);  
    }        
}

大家看上面testSelect这个测试用例,可以看到sqlsessiontemplate的基本使用方法

spring+mybatis注解方式获取dao接口对象的方法:

MapperFactoryBean.getObject

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

这里边的getSqlSession其实就是sqlsessiontemplate。

总结:对于第一部分可以说是返回了mybatis的dao接口的jdk代理对象,通过mapperproxy这个类似于拦截器一样的类跳转执行sql的,可以说是原生dao接口的一层代理对象;

那么对于第二部分来说,确实有三层代理对象


image.png


所以,咱们在spring中使用

@autowired
private UserMapper userMapper;

来注入对象的时候,其实是经历了 cglib --> mapperfactorybean  --> sqlsessiontemplate  --> mapperproxy  -->  原生dao接口  的包装过程,才获取的。

所以咱们在使用spring来调用没有实现类的mybatis的dao接口的时候,并不是像看起来那么简单,而是经过多层代理包装的一个代理对象,对方法的执行也跳转到mybatis框架中的mappermethod中了。

目录
相关文章
|
18天前
|
Java 数据库连接 Maven
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
|
19天前
|
Java 数据库连接 mybatis
SpringBoot配置Mybatis注意事项,mappers层下的name命名空间,要落实到Dao的video类,resultType要落到bean,配置好mybatis的对应依赖。
SpringBoot配置Mybatis注意事项,mappers层下的name命名空间,要落实到Dao的video类,resultType要落到bean,配置好mybatis的对应依赖。
MybatisPlus--IService接口基本用法,MP提供了Service接口,save(T) 这里的意思是新增了一个T, saveBatch 是批量新增的意思,saveOrUpdate是增或改
MybatisPlus--IService接口基本用法,MP提供了Service接口,save(T) 这里的意思是新增了一个T, saveBatch 是批量新增的意思,saveOrUpdate是增或改
|
17天前
|
XML Java 数据格式
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置
|
18天前
|
Java 数据库连接 mybatis
mybatis包扫描环境分析,最简单的环境准备
mybatis包扫描环境分析,最简单的环境准备
|
19天前
|
Java 数据库连接 Maven
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失
Private method ‘getVideoList()‘ is never used,mybatis必须指定Mapper文件和实体目录,在参考其他人写的代码,要认真分析别人的代码,不要丢失
|
28天前
|
存储 Java 数据库连接
SSMP整合案例第三步 业务层service开发及基于Mybatis的接口功能拓展
SSMP整合案例第三步 业务层service开发及基于Mybatis的接口功能拓展
13 0
|
2月前
|
SQL
【MybatisPlus】条件构造器、自定义SQL、Service接口
【MybatisPlus】条件构造器、自定义SQL、Service接口
52 0
【MybatisPlus】条件构造器、自定义SQL、Service接口
|
1月前
|
Java 数据库连接 mybatis
为什么Mybatis Mapper不需要实现类?
在学习Java动态代理之前,我想让大家先思考这样几个问题。 • JDK动态代理为什么不能对类进行代理? • Mybatis Mapper接口为什么不需要实现类? 如果你还不知道上述问题的答案,那么这篇文章一定能消除你心中的疑惑。