Mybatis执行sql流程(二)之加载Mapper

发布于:2025-08-19 ⋅ 阅读:(15) ⋅ 点赞:(0)

Mybatis加载Mapper

注册方式 注册时机 特点
@MapperScan Bean定义阶段注册接口定义 批量注册,推荐方式
@Mapper (接口注解) @MapperScan 需每个接口单独标注
XML 配置 <mapper> MyBatis 初始化时 传统方式,不依赖 Spring 容器
SqlSessionTemplate 直接获取 调用时 编程式获取,不自动注册为 Bean

@MapperScan注册mapper

// 使用:在启动类上添加注解
@MapperScan("com.zy.**.mapper")
@Import(MapperScannerRegistrar.class) // 此处使用了@Import注解,用于导入其他配置
@Repeatable(MapperScans.class)
public @interface MapperScan {
    ...;
}
/**
1.指示要导入的一个或多个组件,通常是@Configuration类。
2.提供与Spring XML中的<import/>元素等效的功能。
3.允许导入@Configuration类,ImportSelector和ImportBeanDefinitionRegistrar实现,以及常规组件类(从4.2开始,类似于AnnotationConfigApplicationContext.register)。
4.导入的@Configuration类中声明的@Bean定义应该使用@Autowired注入来访问。也可以自动连接声明bean的配置类实例。
5.如果需要导入XML或其他非@Configuration bean定义资源,请改用@ImportResource注解。
*/

public @interface Import {

	/**
	 * {@link Configuration @Configuration}, {@link ImportSelector},
	 * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
	 */
	Class<?>[] value();

}

// 实现了ImportBeanDefinitionRegistrar接口,此处涉及到Spring加载BeanDefinition的逻辑
public class MapperScannerRegistrar 
    implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    
    private ResourceLoader resourceLoader;

    // 重写ImportBeanDefinitionRegistrar 接口中的registerBeanDefinitions 方法
    @Override
    public void registerBeanDefinitions(
        AnnotationMetadata importingClassMetadata, 
        BeanDefinitionRegistry registry) {
        
        // 1. 获取@MapperScan注解属性
        AnnotationAttributes mapperScanAttrs = AnnotationAttributes
            .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        
        // 2. 实际注册逻辑
    if (mapperScanAttrs != null) {
      registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
          generateBaseBeanName(importingClassMetadata, 0));
    }
    }

    /**
    annoMeta 被注解类的元数据
    annoAttrs @MapperScan 注解的属性值
    registry : Spring bean 定义注册器
    beanName :要注册的 Bean 名称
    */
  void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
      BeanDefinitionRegistry registry, String beanName) {
// 创建MapperScannerConfigurer 的通用Bean定义构建器。此处还只是构造builder。
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    // 启用属性占位符处理(如 ${jdbc.url})
      builder.addPropertyValue("processPropertyPlaceHolders", true);

      // 注解类过滤:如果设置了annotationClass(如@Mapper),则只扫描带该注解的接口
    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      builder.addPropertyValue("annotationClass", annotationClass);
    }
// 标记接口过滤:如果设置了 markerInterface, 则只扫描实现该接口的Mapper
    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      builder.addPropertyValue("markerInterface", markerInterface);
    }
// Bean 名称生成器
    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);
    }
// SQL 会话模板引用:支持指定特定的 SqlSessionTemplate Bean
    String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
    if (StringUtils.hasText(sqlSessionTemplateRef)) {
      builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
    }
// SQL 会话工厂引用
    String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
    if (StringUtils.hasText(sqlSessionFactoryRef)) {
      builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
    }

    List<String> basePackages = new ArrayList<>();
      // 添加 value 属性值(包路径)
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
// 添加 basePackages 属性值
    basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
        .collect(Collectors.toList()));
// 添加basePackageClasses的包路径
    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);
    }
// Bean 作用域
    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);
// 注册Bean 定义。上述都是在配置builder, 此处才开始注册bean definition
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());

  }
}

MapperScannerConfigurer 作为BeanDefinitionRegistryPostProcessor执行, 中重写了 postProcessBeanDefinitionRegistry 方法,最终调用doScan(basePackages);扫描Mapper

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

    @Override
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // 1. 调用父类扫描方法获取Bean定义
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

        if (beanDefinitions.isEmpty()) {
            logger.warn("No MyBatis mapper was found...");
        } else {
            // 2. 处理扫描到的Bean定义
            processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }
// 省略部分代码
    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        for (BeanDefinitionHolder holder : beanDefinitions) {
            GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();

            // 3. 获取Mapper接口名
            String mapperClassName = definition.getBeanClassName();

            // 4. BeanClass 转换为 MapperFactoryBean
            // 关键步骤1:添加构造参数(原始Mapper接口)
            definition.getConstructorArgumentValues().addGenericArgumentValue(mapperClassName);
            try {
                // 关键步骤2:设置 MapperInterface 属性(Spring Native 兼容)
                definition.getPropertyValues().add("mapperInterface", Resources.classForName(beanClassName));
            } catch (ClassNotFoundException ignore) {
                // ignore
            }
            // 关键步骤3:替换 Bean 类为 MapperFactoryBean
            definition.setBeanClass(this.mapperFactoryBeanClass);

            // 省略部分SqlSessionFactory 、sqlSessionTemplate相关内容。优先级:SqlSessionTemplate > SqlSessionFactory
            
            // 5. 设置自动装配模式:当未显示配置工厂/模板时,启用按类型自动装配
            if (!explicitFactoryUsed) {
                LOGGER.debug("Enabling autowire by type...");
                definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
            }
        }
    }
}

转换前Bean定义:

BeanDefinition {
    beanClass = com.example.UserMapper // 原始接口
    scope = singleton
    ...
}

转换后 Bean 定义

BeanDefinition {
    beanClass = MapperFactoryBean // 替换为工厂类
    constructorArgs = [com.example.UserMapper] // 原始接口作为构造参数
    properties = {
        sqlSessionFactory = ref("sqlSessionFactory") // 自动装配
        addToConfig = true
    }
    ...
}

实际效果:

// 用户代码
@Autowired
UserMapper userMapper; 

// 实际发生
MapperFactoryBean factoryBean = new MapperFactoryBean(UserMapper.class);
factoryBean.setSqlSessionFactory(sqlSessionFactory);
UserMapper proxy = factoryBean.getObject(); // 返回 MyBatis 代理
// MapperFactoryBean 的 getObject() 
@Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface); // 此处就是获取的代理类对象 
  }
// 从 @Autowired 到factoryBean.getObject(); 的过程:
@Autowired
    -> AutowiredAnnotationBeanPostProcessor.postProcessProperties()
        -> InjectionMetadata.inject()
            -> DefaultListableBeanFactory.doGetBean()
                -> AbstractBeanFactory.getObjectForBeanInstance(),发现 MapperFacoryBeanUserMapper 类型的工厂
                    -> AbstractBeanFactory..getObjectFromFactoryBean()
                        -> FactoryBeanRegistrySupport.doGetObjectFromFactoryBean()
                            -> FactoryBean<?>.getObject()
@Autowired Spring容器 DefaultListableBeanFactory FactoryBeanRegistrySupport MapperFactoryBean MyBatis代理 需要注入UserMapper getBean("userMapper") doGetBean("userMapper") getObjectForBeanInstance() doGetObjectFromFactoryBean() getObject() sqlSession.getMapper() MapperProxy 返回代理 返回代理 返回代理 注入代理对象 @Autowired Spring容器 DefaultListableBeanFactory FactoryBeanRegistrySupport MapperFactoryBean MyBatis代理

网站公告

今日签到

点亮在社区的每一天
去签到