Mapper 扫描需要依赖 Maybtis/Spring 这个项目,官方文档:
https://mybatis.org/spring/zh/index.html

Mapper 扫描依赖两种方式:

  1. 通过 @Mapper 注解 (想通过该注解实现扫描 Mapper ,需要依赖 mybatis/spring-boot-starter 这个项目)
  2. 通过 @MapperScan 注解

无论是 @Mapper 还是 @MapeprScan 注解,底层都是需要去注册一个 MapperScannerConfigurer 的 Bean , 然后通过该 Bean 来实现 Mapper 的主动注入。

@Mapper 注解

@Mapper 注解主要使用在 Mapper 接口上,如果要实现只对 @Mapper 注解的接口实现扫描,则需要引入 mybatis/spring-boot-starter 这个项目。
mybatis/spring-boot-starter
使用方法请参考:https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-autoconfigure/src/site/zh/markdown/index.md
AutoConfiguredMapperScannerRegistrar 则是自动扫描 @Mapper 注解接口的实现类。
但是该类启用的条件,必须是 Spring 没有找到 MapperScannerConfigurerMapperFactoryBean 的 bean 。

源码分析

AutoConfiguredMapperScannerRegistrarMybatisAutoConfiguration 的静态内部类,故这里展示的是 MybatisAutoConfiguration 的源码。

/**
 * MybatisAutoConfiguration 是一个配置类 
 * 启用该配置类需要项目存在 SqlSessionFactory 和 SqlSessionFactoryBean 这两个类(这两个类都在 mybatis/spring 项目中)
 * mybatis/spring-boot-starter 会自动引入 mybatis/spring
 */
@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
    // 忽略部分源码,这里只展示要讨论的部分

    /**
     * 对 @Mapper 注解自动扫描的实现类
     * 它继承了 ImportBeanDefinitionRegistrar 接口,实现了 registerBeanDefinitions() 方法
     * registerBeanDefinitions() 方法主要是创建并注册 MapperScannerConfigurer 的 BeanDefinition
     */
    public static class AutoConfiguredMapperScannerRegistrar
            implements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {

        private BeanFactory beanFactory;
        private Environment environment;

        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            // 如果没有配置自动扫描的包路径,那么则终止扫描 Mapper
            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));
            }
            // 创建一个 MapperScannerConfigurer 的 BeanDefinitionBuilder
            // 并且设置 MapperScannerConfigurer 的字段,如 processPropertyPlaceHolders、annotationClass、basePackage 等字段
            // 后续 MapperScannerConfigurer 就会通过这些字段信息去扫描包
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
            builder.addPropertyValue("processPropertyPlaceHolders", true);
            // annotationClass 表示扫描的包中必须要有指定的注解,这里指定要有 Mapper 这个注解
            builder.addPropertyValue("annotationClass", Mapper.class);
            builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
            BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
            Set<String> propertyNames = Stream.of(beanWrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName)
                    .collect(Collectors.toSet());
            if (propertyNames.contains("lazyInitialization")) {
                // Need to mybatis-spring 2.0.2+
                builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
            }
            if (propertyNames.contains("defaultScope")) {
                // Need to mybatis-spring 2.0.6+
                builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");
            }

            // 默认设置 sqlSessionTemplateBeanName 的值为 sqlSessionTemplate  
            boolean injectSqlSession = environment.getProperty("mybatis.inject-sql-session-on-mapper-scan", Boolean.class,
                    Boolean.TRUE);
            if (injectSqlSession && this.beanFactory instanceof ListableBeanFactory) {
                ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;
                Optional<String> sqlSessionTemplateBeanName = Optional
                        .ofNullable(getBeanNameForType(SqlSessionTemplate.class, listableBeanFactory));
                Optional<String> sqlSessionFactoryBeanName = Optional
                        .ofNullable(getBeanNameForType(SqlSessionFactory.class, listableBeanFactory));
                if (sqlSessionTemplateBeanName.isPresent() || !sqlSessionFactoryBeanName.isPresent()) {
                    builder.addPropertyValue("sqlSessionTemplateBeanName",
                            sqlSessionTemplateBeanName.orElse("sqlSessionTemplate"));
                } else {
                    builder.addPropertyValue("sqlSessionFactoryBeanName", sqlSessionFactoryBeanName.get());
                }
            }
            builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

            // 注册 MapperScannerConfigurer 的 BeanDefinition
            registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
        }

        // 忽略后面的代码
    }

    /**
     * 该类使用了 @Configuration 注解,故在调用 AutoConfiguredMapperScannerRegistrar#registerBeanDefinitions() 前,先经过这个类的逻辑:
     * 如果是已经存在了 MapperFactoryBean 或者是 MapperScannerConfigurer 的 Bean
     * 那么就不会加载 AutoConfiguredMapperScannerRegistrar 的 Bean 了,因此也不会去创建 MapperScannerConfigurer 的 BeanDefinition,做后续的 Mapper 扫描了。
     * 其中 MapperScannerConfigurer 的 Bean 可以通过使用 @MapperScan 注解来创建(故如果使用了 @MapperScan 注解,就不会自动扫描 @Mapper 注解的 Mapper)
     * 或者我们自定义了一个 Bean ,返回的是 MapperFactoryBean ,那么也不会自动扫描 @Mapper 注解的 Mapper
     */
    @org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
    @Import(AutoConfiguredMapperScannerRegistrar.class)
    @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
    public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {

        @Override
        public void afterPropertiesSet() {
            logger.debug(
                    "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
        }

    }
}

@MapperScan 注解

@MapperScan 注解是 mybatis 自动扫描的常用方式。
它通过使用了 @Import 注解,导入了 MapperScannerRegistrar 类,并且后续通过 MapperScannerRegistrar 来做 Mapper 扫描的逻辑。
MapperScan 的源码如下:


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
    // 忽略 MapperScan 注解的成员信息
}

MapperScannerRegistrar

MapperScannerRegistrar 与扫描 @Mapper 注解的 AutoConfiguredMapperScannerRegistrar
一样,也是继承了 ImportBeanDefinitionRegistrar 接口,重写了 registerBeanDefinitions 方法。
另外 MapperScannerRegistrar 内部维护了 RepeatingRegistrar 静态类,该类继承了 MapperScannerRegistrar
,功能与 MapperScannerRegistrar 一致,但是给 @MapperScans 注解使用。
故这里只探讨 MapperScannerRegistrar 的源码。

源码分析

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {

    /**
     * 实现了 ImportBeanDefinitionRegistrar 的 registerBeanDefinitions() 方法
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 通过 AnnotationAttributes.fromMap() 方法,获取 @MapperScan 注解的成员变量的值
        // 如果没有使用到 @MapperScan 注解,那么 AnnotationAttributes.fromMap() 方法就会返回 null
        // 说白了就是判断有没有用到 @MapperScan 注解,如果没有用到,就不会自动扫描 Mapper
        AnnotationAttributes mapperScanAttrs = AnnotationAttributes
                .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        if (mapperScanAttrs != null) {
            // 调用下面的方法,去创建 MapperScannerConfigurer 的 BeanDefinition 
            registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
                    generateBaseBeanName(importingClassMetadata, 0));
        }
    }

    /**
     * 创建并注册 MapperScannerConfigurer 的 BeanDefinition
     * 在创建过程中把 @MapperScan 注解的成员变量
     * 都添加到 MapperScannerConfigurer 的 BeanDefinition 的 PropertyValues 上
     */
    void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
        // 先创建 MapperScannerConfigurer 的 BeanDefinition 
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
        // 把 MapperScan 注解的成员变量,都添加到 BeanDefinition 的 PropertyValues 上
        builder.addPropertyValue("processPropertyPlaceHolders", true);

        Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
        if (!Annotation.class.equals(annotationClass)) {
            builder.addPropertyValue("annotationClass", annotationClass);
        }

        Class<?> markerInterface = annoAttrs.getClass("markerInterface");
        if (!Class.class.equals(markerInterface)) {
            builder.addPropertyValue("markerInterface", markerInterface);
        }

        Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
        if (!BeanNameGenerator.class.equals(generatorClass)) {
            builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
        }

        Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
        if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
            builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
        }

        String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
        if (StringUtils.hasText(sqlSessionTemplateRef)) {
            builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
        }

        String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
        if (StringUtils.hasText(sqlSessionFactoryRef)) {
            builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
        }

        List<String> basePackages = new ArrayList<>();

        basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
                .collect(Collectors.toList()));

        basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
                .collect(Collectors.toList()));

        if (basePackages.isEmpty()) {
            basePackages.add(getDefaultBasePackage(annoMeta));
        }

        String lazyInitialization = annoAttrs.getString("lazyInitialization");
        if (StringUtils.hasText(lazyInitialization)) {
            builder.addPropertyValue("lazyInitialization", lazyInitialization);
        }

        String defaultScope = annoAttrs.getString("defaultScope");
        if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {
            builder.addPropertyValue("defaultScope", defaultScope);
        }

        builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));

        // for spring-native
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // 最后注册 BeanDefinition 到 BeanDefinitionRegistry,给后续 Bean 的创建使用
        registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
    }

    private static String generateBaseBeanName(AnnotationMetadata importingClassMetadata, int index) {
        return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
    }

    private static String getDefaultBasePackage(AnnotationMetadata importingClassMetadata) {
        return ClassUtils.getPackageName(importingClassMetadata.getClassName());
    }
}

MapperScannerConfigurer

MapperScannerConfigurer 是 Mapper 自动注入的核心,它实现了以下这些接口:

  • BeanDefinitionRegistryPostProcessor
  • InitializingBean
  • ApplicationContextAware
  • BeanNameAware

其中,自动注入 Mapper 的逻辑,主要是实现了 BeanDefinitionRegistryPostProcessor#registerBeanDefinitions() 方法。

源码如下:

// MapperScannerConfigurer 的一些成员变量,用于给扫描 Mapper 在生成 BeanDefinition 时使用
private String basePackage;
private boolean addToConfig=true;
private String lazyInitialization;
private SqlSessionFactory sqlSessionFactory;
private SqlSessionTemplate sqlSessionTemplate;
private String sqlSessionFactoryBeanName;
private String sqlSessionTemplateBeanName;
private Class<?extends Annotation> annotationClass;
private Class<?> markerInterface;
private Class<?extends MapperFactoryBean> mapperFactoryBeanClass;
private ApplicationContext applicationContext;
private String beanName;
private boolean processPropertyPlaceHolders;
private BeanNameGenerator nameGenerator;
private String defaultScope;

/**
 * 先去创建 ClassPathMapperScanner , 然后调用 ClassPathMapperScanner#scan() 方法去扫描 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.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
        if(StringUtils.hasText(lazyInitialization)){
        scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
        }
        if(StringUtils.hasText(defaultScope)){
        scanner.setDefaultScope(defaultScope);
        }
        scanner.registerFilters();
        scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
        }

从上面的源码中看,实际上是去创建 ClassPathMapperScanner 的类,然后调用 scan() 方法来创建 Mapper。

ClassPathMapperScanner#scan()

ClassPathMapperScannerClassPathBeanDefinitionScanner 的子类,而上面提到的 scan()
方法实际是 ClassPathBeanDefinitionScanner 的。
该方法主要是扫描指定包路径下的 Mapper ,然后转换成 BeanDefinition,这些 BeanDefintion 携带的 beanClass 信息是 MapperFactoryBean 。
并在后续的 Spring Bean 创建流程中,把这些 BeanDefinition 转换成对应的 Bean(本文不讨论 Spring Bean 初始化流程)。

源码如下:

/**
 * ClassPathBeanDefinitionScanner#scan() 方法
 */
public int scan(String...basePackages){
        int beanCountAtScanStart=this.registry.getBeanDefinitionCount();

        // 因为 ClassPathMapperScanner 重写了 doScan() 方法
        // 故这里实际上是调用 ClassPathMapperScanner#doScan() 方法
        doScan(basePackages);

        // Register annotation config processors, if necessary.
        if(this.includeAnnotationConfig){
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }

        return(this.registry.getBeanDefinitionCount()-beanCountAtScanStart);
        }

/**
 * ClassPathMapperScanner#doScan() 方法
 */
public Set<BeanDefinitionHolder> doScan(String...basePackages){
        // 调用 ClassPathBeanDefinitionScanner#doScan() 方法 ,扫描 Mapper
        Set<BeanDefinitionHolder> beanDefinitions=super.doScan(basePackages);

        if(beanDefinitions.isEmpty()){
        if(printWarnLogIfNotFoundMappers){
        LOGGER.warn(()->"No MyBatis mapper was found in '"+Arrays.toString(basePackages)
        +"' package. Please check your configuration.");
        }
        }else{
        // 把扫描得到的 BeanDefinitionHolder 列表元素中的 BeanDefinition 的 beanClass 属性设置成 MapperFactoryBean 类型 
        processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
        }

/**
 * ClassPathBeanDefinitionScanner#doScan() 方法
 * 这里实际上是扫描指定包路径下的 Mapper , 并将它们封装成 BeanDefinitionHolder 列表返回 
 */
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){
        // 从指定包目录下扫描 Mapper
        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);
        // 对 BeanDeifintion 设置默认值
        if(candidate instanceof AbstractBeanDefinition){
        postProcessBeanDefinition((AbstractBeanDefinition)candidate,beanName);
        }
        if(candidate instanceof AnnotatedBeanDefinition){
        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
        }
        // 判断这个 BeanDefinition 是否存在,正常来说是不存在的,如果存在的话,那就证明这个 Mapper 的名字重名或者其他原因。
        // 如果 BeanDefinition 不存在,则添加这个 BeanDefinition 到 BeanDefinitionRegistry 中去
        // 并添加到要返回的 BeanDefinition 列表上,给后续转换 MapperFactoryBean 使用 
        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;
        }

/**
 * ClassPathMapperScanner#processBeanDefinitions()
 * 该方法就是将扫描到的 Mapper 的 BeanDefinitionHolder 的信息进行修改
 * 其中包含了将 BeanDefinitionHolder 的 BeanDefinition 的 beanClass 信息修改成 MapperFactoryBean 的逻辑
 * 因此后面通过 BeanDefinition 所创建出来的 Bean,实际上是 MapperFactoryBean 类型
 */
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions){
        AbstractBeanDefinition definition;
        BeanDefinitionRegistry registry=getRegistry();
        for(BeanDefinitionHolder holder:beanDefinitions){
        definition=(AbstractBeanDefinition)holder.getBeanDefinition();
        boolean scopedProxy=false;
        // 如果这个 BeanDefinition 是一个代理类,那么就去拿它代理的 BeanDefinition
        if(ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())){
        definition=(AbstractBeanDefinition)Optional
        .ofNullable(((RootBeanDefinition)definition).getDecoratedDefinition())
        .map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(()->new IllegalStateException(
        "The target bean definition of scoped proxy bean not found. Root bean definition["+holder+"]"));
        scopedProxy=true;
        }
        String beanClassName=definition.getBeanClassName();
        LOGGER.debug(()->"Creating MapperFactoryBean with name '"+holder.getBeanName()+"' and '"+beanClassName
        +"' mapperInterface");

        // 将 Mapper 全限定类名添加到构造方法的参数进去
        definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
        try{
        // 尝试将 Mapper 全限定类名添加到 BeanDefinition 的 PropertyValues 的 map 中去。
        definition.getPropertyValues().add("mapperInterface",Resources.classForName(beanClassName));
        }catch(ClassNotFoundException ignore){
        // ignore
        }
        // 修改 BeanClass 的信息,把 Mapper 的 class 替换成 MapperFactoryBean
        definition.setBeanClass(this.mapperFactoryBeanClass);

        // 下面的代码,都是将 ClassPathMapperScanner 的成员变量的信息,都添加到 BeanDifinition 的 PropertyValues 中去。
        definition.getPropertyValues().add("addToConfig",this.addToConfig);

        // Attribute for MockitoPostProcessor
        // https://github.com/mybatis/spring-boot-starter/issues/475
        definition.setAttribute(FACTORY_BEAN_OBJECT_TYPE,beanClassName);

        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){
        LOGGER.debug(()->"Enabling autowire by type for MapperFactoryBean with name '"+holder.getBeanName()+"'.");
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }

        definition.setLazyInit(lazyInitialization);

        if(scopedProxy){
        continue;
        }

        if(ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope())&&defaultScope!=null){
        definition.setScope(defaultScope);
        }

        // 对非单例类型的 Mapper 做的逻辑
        if(!definition.isSingleton()){
        BeanDefinitionHolder proxyHolder=ScopedProxyUtils.createScopedProxy(holder,registry,true);
        if(registry.containsBeanDefinition(proxyHolder.getBeanName())){
        registry.removeBeanDefinition(proxyHolder.getBeanName());
        }
        registry.registerBeanDefinition(proxyHolder.getBeanName(),proxyHolder.getBeanDefinition());
        }

        }
        }

MapperFactoryBean

MapperFactoryBean 是 Mybatis/Spring 用来表示 Mapper 的 Bean ,它继承了 SqlSessionDaoSupport ,实现了 FactoryBean 接口。
所以在获取 Mapper 对应的 Bean 时,实际上是调用了 FactoryBean#getObject() 方法(关于 FactoryBean
的使用,具体可以去搜索引擎查询,这里就不过不叙述了),返回 MapperProxy 的代理类。
以下为 MapperFactoryBean 的部分源码:

/**
 * 只展示要讨论的部分,隐藏掉部分不重要的代码
 */
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    /**
     * 该 MapperFactoryBean 所对应的 Mapper class 信息
     */
    private Class<T> mapperInterface;

    /**
     * 实现了 FactoryBean#getObject() 方法
     * 内部逻辑其实就是调用了 SqlSessionTemplate#getMapper() 方法
     * 返回 Mapper 的代理对象,也就是 MapperProxy 代理类
     */
    @Override
    public T getObject() throws Exception {
        // MapperFactoryBean 继承的 SqlSessionDaoSupport 抽象类,内部维护了 SqlSessionTemplate 这个对象
        // getSqlSession() 方法,实际就是返回 SqlSessionTemplate 这个对象
        return getSqlSession().getMapper(this.mapperInterface);
    }
}

SqlSessionTemplate

SqlSessionTemplate 是线程安全的,以保证与当前事务挂钩。
它基于 Spring 事务来完成事务的提交和回滚操作,它不支持调用 SqlSessionTemplatecommit()rollback()close() 等与事务有关的操作。

以下为 SqlSessionTemplate 的部分源码:

public class SqlSessionTemplate implements SqlSession, DisposableBean {
    private final SqlSessionFactory sqlSessionFactory;

    /**
     * SqlSessionFactory 内部维护了 Configuration 对象
     * 而 Configuration 内部维护了 MapperRegistry 对象
     * Configuration#getMapper() 方法则是从 MapperRegistry 里面获取 Mapper 的代理对象,也就是 MapperProxy
     */
    @Override
    public <T> T getMapper(Class<T> type) {
        // 从 Configuration 里面获取 Mapper 的代理对象
        return getConfiguration().getMapper(type, this);
    }

    @Override
    public Configuration getConfiguration() {
        return this.sqlSessionFactory.getConfiguration();
    }
}

Configratuion 和 MapperRegistry

org.apache.ibatis.session.Configuration 类主要是维护了 MyBatis 的配置信息,其中包含了 Mapper 的信息。
其中它内部维护的 MapperRegistry 存放了 Mapper 的信息。

以下为 MapperRegistry 的部分源码:

public class MapperRegistry {

    private final Configuration config;
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

    public MapperRegistry(Configuration config) {
        this.config = config;
    }

    @SuppressWarnings("unchecked")
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        }
        try {
            // 通过动态代理去创建一个代理类出来,对应类型为 MapperProxy 这个类
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
            throw new BindingException("Error getting mapper instance. Cause: " + e, e);
        }
    }
}

从上面的代码中,我们可以看到,每次通过 MapperRegistry 获取 Mapper 的时候,会创建一个新的 MapperProxy 代理对象。
如果我们只通过 MapperRegistry 来获取 Mapper 的代理对象,那么每获取一次,相当于要创建一个新的 MapperProxy 。
而 MyBatis/Spring 通过 MapperFactoryBean ,保证每次去获取 Mapper 的 Bean 对象前,会去 Bean 的缓存中获取 Mapper 。
如果 Bean 的缓存不存在该 Mapper ,才去调用 Mapper 对应的 MapperFactoryBean#getObject() 方法,去创建和获取一个新的 MapperProxy 代理对象。


yosoro
1 声望0 粉丝

this guy is lazy , nothing to write down