首先依赖于springboot的自动装配@EnableAutoConfiguration注解,这个注解最终帮助我们读取mybatis-spring-boot-autoconfigure-x.x.x.jar中的META-INF\spring.factories配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
来看MybatisAutoConfiguration的源码,最主要的就是AutoConfiguredMapperScannerRegistrar。
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {//...@Configuration@Import({AutoConfiguredMapperScannerRegistrar.class})@ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {public MapperScannerRegistrarNotFoundConfiguration() {}public void afterPropertiesSet() {MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");}}public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {private BeanFactory beanFactory;public AutoConfiguredMapperScannerRegistrar() {}public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {if (!AutoConfigurationPackages.has(this.beanFactory)) {MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");} else {// 这里获取要扫描的包名MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");List<String> packages = AutoConfigurationPackages.get(this.beanFactory);if (MybatisAutoConfiguration.logger.isDebugEnabled()) {packages.forEach((pkg) -> {MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);});}// 下面这些代码主要就是定义一个bean的定义,添加到BeanFactory中 BeanDefinitionBuilderBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders", true);// 这就是要扫描的注解类型,就是@Mapperbuilder.addPropertyValue("annotationClass", Mapper.class);// //这里是要扫描的包的路径builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);Set<String> propertyNames = (Set)Stream.of(beanWrapper.getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());if (propertyNames.contains("lazyInitialization")) {builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");}if (propertyNames.contains("defaultScope")) {builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");}registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());}}public void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}}
}
AutoConfiguredMapperScannerRegistrar主要就是把MapperScannerConfigurer这个类注册到spring中,来看MapperScannerConfigurer的代码:
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {//...@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {if (this.processPropertyPlaceHolders) {//这个是主要设置一些属性,比如上面包名,要扫描的注解类名称等等processPropertyPlaceHolders();}//这个类看名字都知道是干什么的, 主要就是扫描mapper注解的类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));}// ...
}
由于MapperScannerConfigurer这个类实现了BeanDefinitionRegistryPostProcessor,所以它就会被生成bean之前加载,调用它的postProcessBeanDefinitionRegistry方法,postProcessBeanDefinitionRegistry里面就会scan我们指定的package里的@Mapper类。再来看ClassPathMapperScanner:
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {//...@Overridepublic 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 {processBeanDefinitions(beanDefinitions);}return beanDefinitions;}private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {GenericBeanDefinition definition;for (BeanDefinitionHolder holder : beanDefinitions) {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//这里是给bean定义的添加一个构造方法参数,就是我们扫描出来mapper注解类的类名definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59// 这个就是设置对应bean的类的类,这里设置成了org.mybatis.spring.mapper.MapperFactoryBean这个类,这注意这个类实现了FactoryBean接口definition.setBeanClass(this.mapperFactoryBean.getClass());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);}}}//...
}
最终在获取bean的时候,会调用MapperFactoryBean这个类的getObject()
:
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {private Class<T> mapperInterface;// ...public MapperFactoryBean(Class<T> mapperInterface) {this.mapperInterface = mapperInterface;}/*** {@inheritDoc}*/@Overridepublic T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);}/*** {@inheritDoc}*/@Overridepublic Class<T> getObjectType() {return this.mapperInterface;}//....
}
getObject()
里会返回代理对象,对象的类型即 构造函数里传进来的 mapperInterface 。
的加载,beanFatory加载@Mapper类