Problem description
@MapperScan annotation is generally configured to use dao or mapper's scanning package to operate the database, which is generally an interface. If there are other interfaces in dao layer, such as @ Service, an error will be reported
Solution 1
Remove the service package. The method is feasible
Solution 2
Do not use @ MapperScan. Add @ Mapper annotation to each dao or Mapper. The method is feasible
Solution 3
With user-defined annotations, you don't need to do much by yourself when mybatis's annotations are relatively complete
1. Create annotation @ MyMapperScan
All the attributes in it are copied from @ MapperScan
MapperScannerRegistrar to its own
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(MyMapperScannerRegistrar.class) @Repeatable(MapperScans.class) public @interface MapperScan { String[] value() default {}; String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; Class<? extends Annotation> annotationClass() default Annotation.class; Class<?> markerInterface() default Class.class; String sqlSessionTemplateRef() default ""; String sqlSessionFactoryRef() default ""; Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class; String lazyInitialization() default ""; }
Mymapperscannerregistratir scan registrar
This class is exactly the same as mybatis. The only difference is that MyClassPathMapperScanner is its own scan.
public class MyMapperScannerRegistrar extends MapperScannerRegistrar { private ResourceLoader resourceLoader; /** * {@inheritDoc} */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); //This is my own ClassPathMapperScanner scanner = new MyClassPathMapperScanner(registry); // this check is needed in Spring 3.1 if (resourceLoader != null) { scanner.setResourceLoader(resourceLoader); } Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass"); if (!Annotation.class.equals(annotationClass)) { scanner.setAnnotationClass(annotationClass); } Class<?> markerInterface = annoAttrs.getClass("markerInterface"); if (!Class.class.equals(markerInterface)) { scanner.setMarkerInterface(markerInterface); } Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator"); if (!BeanNameGenerator.class.equals(generatorClass)) { scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass)); } Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean"); if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) { scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass)); } scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef")); scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef")); List<String> basePackages = new ArrayList<String>(); for (String pkg : annoAttrs.getStringArray("value")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (String pkg : annoAttrs.getStringArray("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } scanner.registerFilters(); scanner.doScan(StringUtils.toStringArray(basePackages)); } /** * {@inheritDoc} */ @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } }
MyClassPathMapperScanner
My own scanning class is also mybatis, which is a little bit changed in judgment
public class MyClassPathMapperScanner extends ClassPathMapperScanner { public MyClassPathMapperScanner(BeanDefinitionRegistry registry) { super(registry); } @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { boolean flag = super.isCandidateComponent(beanDefinition); //The package with Mapper will be represented by mybatis boolean mapper = beanDefinition.getBeanClassName().contains("Mapper"); return flag && mapper; } }
Now you only need to use your own scanning annotation, which is exactly the same as mybatis.
Solution 4
This is for the third point. When the author uses the third point, mybatis version is 3.4.6
Mybatis spring version 1.3.2, spring version 5.x
When mybatis spring version 3.5.2 is 2.0.2
The way MapperScannerRegistrar class scans has changed a little,
The MapperScannerConfigurer class needs to be overridden, and the others remain unchanged
Complete!
Others can refer to other articles of the author spring custom component scanning, imitating @ MapperScan