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

    xiaoxiao2021-03-25  81

    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); }
    转载请注明原文地址: https://ju.6miu.com/read-40756.html

    最新回复(0)