@MapperScan 扫描包流程分析

武培轩

共 12628字,需浏览 26分钟

 ·

2021-06-08 23:46

以下文章来源于武培轩,回复资源获取资料

前言

其实一般不写这样的分析的,但是这次呢一是为了记录下来分析过程,二是给大家分享一下@MapperScan注解扫描包的流程吧。

提出问题

@MapperScan("com.fast")扫描的是com.fast这个包下面的bean是毋庸置疑的,但是包括子包下面的bean吗?

疑问案例

比如com.fast.master.dao,还有com.fast.second.dao这些包下面的bean是否会一起被扫描到?

分析

  1. 查看MapperScan注解,扫描包主要是这个@Import({MapperScannerRegistrar.class})
@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;
}
  1. 找到MapperScannerRegistrar.class看实现过程,就不全贴了,主要是这个注解这一块
    void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        Optional var10000 = Optional.ofNullable(this.resourceLoader);
        Objects.requireNonNull(scanner);
        var10000.ifPresent(scanner::setResourceLoader);
        Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
        if (!Annotation.class.equals(annotationClass)) {
            scanner.setAnnotationClass(annotationClass);
        }
        Class<?> markerInterface = annoAttrs.getClass("markerInterface");
        if (!Class.class.equals(markerInterface)) {
            scanner.setMarkerInterface(markerInterface);
        }
        Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
        if (!BeanNameGenerator.class.equals(generatorClass)) {
            scanner.setBeanNameGenerator((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
        }
        Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
        if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
            scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);
        }
        scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
        scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
        List<String> basePackages = new ArrayList();
        basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
        basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
        basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(basePackages));
    }

这句周围的是不是很熟悉,就是MapperScan实现的注解,value,basePackages,basePackageClasses这几个

basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));

从scanner.doScan这句进去,这里是开始扫描包的地方

  1. 打开调用的方法
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        Iterator var3 = beanDefinitions.iterator();

        while(var3.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
            GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
            String beanClassName = definition.getBeanClassName();
            LOGGER.debug(() -> {
                return "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface";
            });
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
            definition.setBeanClass(this.mapperFactoryBeanClass);
            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(() -> {
                        return "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(() -> {
                        return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.";
                    });
                }
                definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
                explicitFactoryUsed = true;
            }
     
            if (!explicitFactoryUsed) {
                LOGGER.debug(() -> {
                    return "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.";
                });
                definition.setAutowireMode(2);
            }
        }
    }
  1. 从这个方法第一行开始debug,这里我使用@MapperScan("com.fast.framework.dao") 是扫描的com.fast.framework.dao包

这个是扫描到的包,说明会扫描到子包,perfect,解决了开始提出的问题。

总结

其实这里的分析过程不是特别详细,因为到这里是证明扫描出来的包,从而间接证明扫描到的包都会被使用。剩下的:上一步怎么扫描的全部包,还有扫描到包怎么初始化的都没有详细分析。所以也是小水一篇吧,主要是要明白@MapperScan注解会扫描包的子包和学会这种分析思路。

来源:blog.csdn.net/Mint6/article/details/92441513

觉得不错,请点个在看

浏览 118
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报