[mybatis]自动扫描整个项目的mapper(并解决接口冲突)

4 篇文章 0 订阅
1 篇文章 0 订阅

mybatis的注解使用非常简便(因为不用编写一大堆xml语句)。
网上给出的使用教程简化如下
1.在spring配置文件添加以下bean

    <!-- 配置数据源,使用dbcp -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://111.11.11.111:3306/database"></property>
        <property name="username" value="root"></property>
        <property name="password" value="*******"></property>
        <property name="maxActive" value="10"></property>
        <property name="maxIdle" value="5"></property>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >

        <!-- 加载mybatis的配置信息 -->
        <!--<property name="configLocation" value="cn/labelnet/mybatis/config/SqlmapDaoConfig.xml"></property>-->

        <!-- 加载数据源  dataSource-->
        <property name="dataSource" ref="dataSource"></property>

    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--com.dao是mapper类所在的包-->
        <property name="basePackage" value="cn.dao"/>
        <!--下面这个省略掉的话也不会出错,建议保留它-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

里面的类中最关键的是MapperScannerConfigurer,自动扫描就是在这里实现的。

2.再写个mapper接口就行了

public interface UserMapper {
    @Insert("insert into User(uid,wxid,createTime,lastTime) values(#{uid},#{wxid},#{createTime},#{lastTime})")
    public void insert(User user);

    @Delete("delete from User where uid=#{uid}")
    public void deleteById(String uid);

    @Update("update User set wxid=#{wxid},lastTime=#{lastTime} where uid=#{uid}")
    public void updateT(User user);

    @Select("select * from User where uid=#{uid}")
    public User getUser(String uid);
}

网上的教程都是把basePackage固定再一个dao包中,但我却想不管mapper接口在那,mybatis都能自动生成对应的类。

最简单的方法当然是把basePackage的value改成根包了。而这时spring会报出一个bean不唯一的异常

nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [cn.pingweb.service.ITeacherService] is defined: expected single matching bean but found 2: teacherServiceImpl,ITeacherService

解决问题

百度一番没什么结果,当然就去看源码了。

MapperScannerConfigurer对mapper的扫描注册可以在这里开始看

  @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);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    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));
  }

接着看ClassPathMapperScanner,其中registerFilters方法负责过滤扫描到的接口。再结合其他信息,我们可以分析到网上的教程都把basePackage固定再一个dao包中是很有道理的!因为mybatis会为basePackage范围内的每一个接口都自动生成一个类!这个就是报错的原因。


  /**
   * Configures parent scanner to search for the right interfaces. It can search
   * for all interfaces or just for those that extends a markerInterface or/and
   * those annotated with the annotationClass
   */
  public void registerFilters() {
    boolean acceptAllInterfaces = true;

    // if specified, use the given annotation and / or marker interface
    if (this.annotationClass != null) {
      addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
      acceptAllInterfaces = false;
    }

    // override AssignableTypeFilter to ignore matches on the actual marker interface
    if (this.markerInterface != null) {
      addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
        @Override
        protected boolean matchClassName(String className) {
          return false;
        }
      });
      acceptAllInterfaces = false;
    }

    if (acceptAllInterfaces) {
      // default include filter that accepts all classes
      addIncludeFilter(new TypeFilter() {
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
          return true;
        }
      });
    }

    // exclude package-info.java
    addExcludeFilter(new TypeFilter() {
      @Override
      public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        String className = metadataReader.getClassMetadata().getClassName();
        return className.endsWith("package-info");
      }
    });
  }

再来看下上面方法中的这个,可见我们通过添加一个自定义注解把不是mapper的接口过滤掉

    if (this.annotationClass != null) {
      addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
      acceptAllInterfaces = false;
    }

而this.annotationClass是在MapperScannerConfigurer传入的

所以我们如下只要改一下配置(注入annotationClass属性),添加一个自定义注解就行了

代码如下

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--com.dao是mapper类所在的包-->
        <property name="basePackage" value="cn.dao"/>
        <!--下面这个省略掉的话也不会出错,建议保留它-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
        <!--下面这个省略掉的话也不会出错,建议保留它-->
        <property name="annotationClass" value="framework.database.annotation.Dao"/>
    </bean>
package framework.database.annotation;

public @interface Dao {
}
@Dao
public interface UserMapper {
    @Insert("insert into User(uid,wxid,createTime,lastTime) values(#{uid},#{wxid},#{createTime},#{lastTime})")
    public void insert(User user);

    @Delete("delete from User where uid=#{uid}")
    public void deleteById(String uid);

    @Update("update User set wxid=#{wxid},lastTime=#{lastTime} where uid=#{uid}")
    public void updateT(User user);

    @Select("select * from User where uid=#{uid}")
    public User getUser(String uid);
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值