Spring Boot应用启动后,会扫描Mybatis自动装配类MybatisAutoConfiguration,该类中定义了内部类AutoConfiguredMapperScannerRegistrar和MapperScannerRegistrarNotFoundConfiguration,其中MapperScannerRegistrarNotFoundConfiguration是一个配置类(添加了@Configuration),同时它导入(@Import)了内部类AutoConfiguredMapperScannerRegistrar,而内部类AutoConfiguredMapperScannerRegistrar又实现了ImportBeanDefinitionRegistrar接口,于是在装配AutoConfiguredMapperScannerRegistrar的时候,AutoConfiguredMapperScannerRegistrar会调用方法registerBeanDefinitions往Spring IoC容器中注册自定义bean definitions,这里的bean是MapperScannerConfigurer。
/** * This will just scan the same base package as Spring Boot does. If you want more power, you can explicitly use * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box, * similar to using Spring Data JPA repositories. */ publicstaticclassAutoConfiguredMapperScannerRegistrarimplementsBeanFactoryAware, ImportBeanDefinitionRegistrar{ private BeanFactory beanFactory; @Override publicvoidregisterBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ if (!AutoConfigurationPackages.has(this.beanFactory)) { logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled."); return; } logger.debug("Searching for mappers annotated with @Mapper"); List<String> packages = AutoConfigurationPackages.get(this.beanFactory); if (logger.isDebugEnabled()) { packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg)); } BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); builder.addPropertyValue("processPropertyPlaceHolders", true); builder.addPropertyValue("annotationClass", Mapper.class); builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages)); BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class); Stream.of(beanWrapper.getPropertyDescriptors()) // Need to mybatis-spring 2.0.2+ .filter(x -> x.getName().equals("lazyInitialization")).findAny() .ifPresent(x -> builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}")); registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition()); } }
... /** * If mapper registering configuration or mapper scanning configuration not present, this configuration allow to scan * mappers based on the same component-scanning path as Spring Boot itself. */ @org.springframework.context.annotation.Configuration @Import(AutoConfiguredMapperScannerRegistrar.class) @ConditionalOnMissingBean({ MapperFactoryBean.class, MapperScannerConfigurer.class }) publicstaticclassMapperScannerRegistrarNotFoundConfigurationimplementsInitializingBean{ @Override publicvoidafterPropertiesSet(){ logger.debug( "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer."); } }
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { if (explicitFactoryUsed) { LOGGER.warn(() -> { return"Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."; }); }
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); explicitFactoryUsed = true; } elseif (this.sqlSessionTemplate != null) { if (explicitFactoryUsed) { LOGGER.warn(() -> { return"Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."; }); }
if (!explicitFactoryUsed) { LOGGER.debug(() -> { return"Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."; }); definition.setAutowireMode(2); } }
/** * Perform a scan within the specified base packages. * @param basePackages the packages to check for annotated classes * @return number of beans registered */ publicintscan(String... basePackages){ int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary. if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }
/** * Perform a scan within the specified base packages, * returning the registered bean definitions. * <p>This method does <i>not</i> register an annotation config processor * but rather leaves this up to the caller. * @param basePackages the packages to check for annotated classes * @return set of beans registered if any for tooling registration purposes (never {@code null}) */ protected Set<BeanDefinitionHolder> doScan(String... basePackages){ Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
privatefinal Configuration config; // 注册表,key:mapper interface,value: MapperProxyFactory privatefinal Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>(); publicMapperRegistry(Configuration config){ this.config = config; } /** * 从注册表中获取MapperProxyFactory */ @SuppressWarnings("unchecked") public <T> T getMapper(Class<T> type, SqlSession sqlSession){ final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { thrownew BindingException("Type " + type + " is not known to the MapperRegistry."); } try { // 传入sqlSession,动态实例化type,即mapper interface return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { thrownew BindingException("Error getting mapper instance. Cause: " + e, e); } } public <T> booleanhasMapper(Class<T> type){ return knownMappers.containsKey(type); }
/** * 添加到注册表中 */ public <T> voidaddMapper(Class<T> type){ if (type.isInterface()) { if (hasMapper(type)) { thrownew BindingException("Type " + type + " is already known to the MapperRegistry."); } boolean loadCompleted = false; try { knownMappers.put(type, new MapperProxyFactory<>(type)); // It's important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. If the type is already known, it won't try. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } } /** * @since 3.2.2 */ public Collection<Class<?>> getMappers() { return Collections.unmodifiableCollection(knownMappers.keySet()); } /** * @since 3.2.2 */ publicvoidaddMappers(String packageName, Class<?> superType){ ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>(); resolverUtil.find(new ResolverUtil.IsA(superType), packageName); Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses(); for (Class<?> mapperClass : mapperSet) { addMapper(mapperClass); } } /** * @since 3.2.2 */ publicvoidaddMappers(String packageName){ addMappers(packageName, Object.class); }