Mybatis MapperScannerConfigurer自动扫描Mapper接口生成代理注入到Spring的方法
前言
MybatisMapperScannerConfigurer自动扫描将Mapper接口生成代理注入到SpringMybatis在与Spring集成的时候可以配置MapperFactoryBean来生成Mapper接口的代理。
例如:
MapperFactoryBean创建的代理类实现了UserMapper接口,并且注入到应用程序中。因为代理创建在运行时环境中(Runtime,译者注),那么指定的映射器必须是一个接口,而不是一个具体的实现类。
上面的配置有一个很大的缺点,就是系统有很多的配置文件时全部需要手动编写,所以上述的方式已经很用了。
没有必要在Spring的XML配置文件中注册所有的映射器。相反,你可以使用一个MapperScannerConfigurer,它将会查找类路径下的映射器并自动将它们创建成MapperFactoryBean。
要创建MapperScannerConfigurer,可以在Spring的配置中添加如下代码:
basePackage属性是让你为映射器接口文件设置基本的包路径。你可以使用分号或逗号作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到。
注意,没有必要去指定SqlSessionFactory或SqlSessionTemplate,因为MapperScannerConfigurer将会创建MapperFactoryBean,之后自动装配。但是,如果你使用了一个以上的DataSource,那么自动装配可能会失效。这种情况下,你可以使用sqlSessionFactoryBeanName或sqlSessionTemplateBeanName属性来设置正确的bean名称来使用。这就是它如何来配置的,注意bean的名称是必须的,而不是bean的引用,因此,value属性在这里替代通常的ref。
整体配置如下所示:
MapperScannerConfigurer支持过滤由指定的创建接口或注解创建映射器。annotationClass属性指定了要寻找的注解名称。markerInterface属性指定了要寻找的父接口。如果两者都被指定了,加入到接口中的映射器会匹配两种标准。默认情况下,这两个属性都是null,所以在基包中给定的所有接口可以作为映射器加载。
被发现的映射器将会使用Spring对自动侦测组件(参考Spring手册的3.14.4)默认的命名策略来命名。也就是说,如果没有发现注解,它就会使用映射器的非大写的非完全限定类名。但是如果发现了@Component或JSR-330的@Named注解,它会获取名称。注意你可以配置到org.springframework.stereotype.Component,javax.inject.Named(如果你使用JSE6的话)或你自己的注解(肯定是自我注解)中,这样注解将会用作生成器和名称提供器。
接下来让我们看一下MapperScannerConfigurer类的源码看看是如何自动扫描的。
/** *{@inheritDoc} * *@since1.0.2 */ @Override publicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry){ if(this.processPropertyPlaceHolders){ processPropertyPlaceHolders(); } ClassPathMapperScannerscanner=newClassPathMapperScanner(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)); }
把Mapper接口转换成MapperFactoryBean的代码在scanner.scan方法里,让我们跟踪进去看一下。
/** *Performascanwithinthespecifiedbasepackages. *@parambasePackagesthepackagestocheckforannotatedclasses *@returnnumberofbeansregistered */ publicintscan(String...basePackages){ intbeanCountAtScanStart=this.registry.getBeanDefinitionCount(); doScan(basePackages); //Registerannotationconfigprocessors,ifnecessary. if(this.includeAnnotationConfig){ AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } return(this.registry.getBeanDefinitionCount()-beanCountAtScanStart); }
/** *Performascanwithinthespecifiedbasepackages, *returningtheregisteredbeandefinitions. *Thismethoddoesnotregisteranannotationconfigprocessor *butratherleavesthisuptothecaller. *@parambasePackagesthepackagestocheckforannotatedclasses *@returnsetofbeansregisteredifanyfortoolingregistrationpurposes(never{@codenull}) */ protectedSet
doScan(String...basePackages){ Assert.notEmpty(basePackages,"Atleastonebasepackagemustbespecified"); Set beanDefinitions=newLinkedHashSet (); for(StringbasePackage:basePackages){ Set candidates=findCandidateComponents(basePackage); for(BeanDefinitioncandidate:candidates){ ScopeMetadatascopeMetadata=this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); StringbeanName=this.beanNameGenerator.generateBeanName(candidate,this.registry); if(candidateinstanceofAbstractBeanDefinition){ postProcessBeanDefinition((AbstractBeanDefinition)candidate,beanName); } if(candidateinstanceofAnnotatedBeanDefinition){ AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate); } if(checkCandidate(beanName,candidate)){ BeanDefinitionHolderdefinitionHolder=newBeanDefinitionHolder(candidate,beanName); definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder,this.registry); } } } returnbeanDefinitions; }
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。