Mybatis源码解析--Spring管理Mapper代理对象

前言

在解析代码之前,我们先回顾一下spring容器是怎么管理bean的

  1. 对bean(xml配置,注解标识)进行解析生成BeanDefinition对象,注册到BeanDefinitionRegistry容器中

  2. 实例化容器中所有实现了BeanFactoryPostProcessor接口的bean,执行postProcessBeanFactory方法

  3. 实例化容器中所有的单例bean,并填充bean的属性

  4. 执行所有实现了BeanPostProcessor接口bean的postProcessBeforeInitialization方法

  5. 执行bean的初始化方法(定义bean时配置的init-method方法,或实现InitializingBean接口重写的afterPropertiesSet方法)

  6. 执行所有实现了BeanPostProcessor接口bean的postProcessAfterInitialization方法

Mapper文件是通过MapperScan注解将Mapper扫描放到Spring容器中的,我们就从MapperScan注解开始分析

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan {
	
    String[] value() default {};

    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends Annotation> annotationClass() default Annotation.class;

    Class<?> markerInterface() default Class.class;

    String sqlSessionTemplateRef() default "";

    String sqlSessionFactoryRef() default "";

    Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;

    String lazyInitialization() default "";

    String defaultScope() default "";

MapperScans注解导入了MapperScannerRegistrar类,MapperScannerRegistrar类是ImportBeanDefinitionRegistrar接口的实现类,重写了registerBeanDefinitions方法

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    public MapperScannerRegistrar() {
    }

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        if (mapperScanAttrs != null) {
            this.registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0));
        }

    }

registerBeanDefinitions中通过AnnotationAttributes工具类获取了MapperScan注解的属性,然后调用重载的registerBeanDefinitions方法

 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    private boolean addToConfig = true;
    private SqlSessionFactory sqlSessionFactory;
    private SqlSessionTemplate sqlSessionTemplate;
    private String sqlSessionTemplateBeanName;
    private String sqlSessionFactoryBeanName;
    private Class<? extends Annotation> annotationClass;
    private Class<?> markerInterface;
    private MapperFactoryBean<?> mapperFactoryBean = new MapperFactoryBean();

    public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
        super(registry, false);
    }

这个是mybatis继承spring的ClassPathBeanDefinitionScanner类扫描器,加了一些mybatis需要用到的属性

  scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
        scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
        List<String> basePackages = new ArrayList();
        String[] var10 = annoAttrs.getStringArray("value");
        int var11 = var10.length;

        int var12;
        String pkg;
        for(var12 = 0; var12 < var11; ++var12) {
            pkg = var10[var12];
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }

        var10 = annoAttrs.getStringArray("basePackages");
        var11 = var10.length;

        for(var12 = 0; var12 < var11; ++var12) {
            pkg = var10[var12];
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
	调用的doScan方法
	scanner.doScan(StringUtils.toStringArray(basePackages));

在registerBeanDefinitions中获取注解中的属性信息,然后设置给ClassPathBeanDefinitionScanner的对象。遍历注解中设置的包路径放到集合中

  public Set<BeanDefinitionHolder> doScan(String... basePackages) {
  		调用父类的扫描包方法
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions.isEmpty()) {
            this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
        } else {
            this.processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }

    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        Iterator var3 = beanDefinitions.iterator();

        while(var3.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
           从holder里获取到BeanDefinition
            GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface");
            }
			设置构造函数的参数为当前类的类名,也就是mapper接口
            definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
            设置beanClass为Mapper的工厂类
            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;
            }

上面的代码首先调用了父类的doscan方法,获取到了BeanDefinitionHolder,BeanDefinitionHolder里面有BeanDefinition和beanNmae以及别名。然后从BeanDefinitionHolder里面获取到BeanDefinition。设置它的beanClass为this.mapperFactoryBean.getClass(),spring容器在实例化bean的时候根据BeanDefinition的beanClass属性创建,所以会创建MapperFactoryBean对象。又给BeanDefinition的属性增加了几个PropertyValue配置。在创建MapperFactoryBean的时候会自动填充这些属性。
MapperFactoryBean是继承了FactoryBean的工厂类。工厂类返回的对象是getObject对象返回的,所以我们根据指定的类型获取Mapper的时候,是从容器中拿到MapperFactoryBean的getObject()方法返回的对象

 public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
}

getObject方法是从SqlSession里面的configuration属性中获取Mapper类,我们的Mapper通过动态代理创建好后会放在configuration主配置文件类的mapperRegistry中

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
	        return this.mapperRegistry.getMapper(type, sqlSession);
}
总结

整个流程就是,MapperScan注解中引入了MapperScannerRegistrar类。这个类创建了继承ClassPathBeanDefinitionScanner的ClassPathMapperScanner类。获取注解里面的包路径放到集合里面,调用父类的doscan方法获取BeanDefinitionHolder对象,给后面需要实例化的BeanDefinition对象设置构造参数为当前mapper文件的类名,设置BeanClass为当前对象的mapperFactoryBean属性。当我们根据Mapper类型从Spring容器中获取FactoryBean时,获取到的是FactoryBean的getObject()方法返回的对象。之前看到apollo的@EnableApolloConfig注解,也是使用了类似的方式去管理对象,有兴趣的可以去研究一下

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值