spring-源码-@ComponentScan

前言

  1. 通过分析我们知道这个启动类是什么时候被注册的
  2. 通过分析我们知道了这个 @ComponentScan 是什么时候被使用到的
  3. 需要说明的是这里仅仅涉及到 Class 转成 BeanDefinition 的过程,并不涉及 对象创建等操作…
  4. 其实这里仅仅是处理 @Component 或者说仅仅去扫描 @Component 注解和 派生注解.

启动类

@ComponentScan
public class ComponentScanContext {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ComponentScanContext .class);
    }
}

处理启动类

  1. new AnnotationConfigApplicationContext() – 容器初始化对象
  2. register() – 注册
  3. register() – 注册
  4. registerBean – 注册这个Bean
  5. doRegisterBean() – 去注册这个Bean,也就是说去注册
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
                                @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
                                @Nullable BeanDefinitionCustomizer[] customizers) {
    // 将 Bean 配置类信息转成容器中 AnnotatedGenericBeanDefinition
    // AnnotatedGenericBeanDefinition 继承自 BeanDefinition 作用是定义一个bean的数据结构,
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
	
    //解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    
    //生成bean配置类beanName
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    
    //通用注解解析到 abd 结构中,主要是处理 Lazy, primary DependsOn, Role ,Description 这五个注解
    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

    //这类:简单理解就是将 AnnotatedGenericBeanDefinition 和beanName 做一个映射
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
 
    //创建代理对象
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    
    // 实际上DefaultListableBeanFactory内部维护一个Map<String, BeanDefinition>类型变量beanDefinitionMap,
    // 用于保存注bean定义信息(beanname 和 beandefine映射)
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

处理@ComponentScan

  1. new AnnotationConfigApplicationContext() – 容器初始化对象
  2. refresh() 刷新容器
  3. 执行 invokeBeanFactoryPostProcessors,简单说是初始化一些BeanFactoryPostProcessors
  4. invokeBeanFactoryPostProcessors(); 简单说是初始化一些BeanFactoryPostProcessors
  5. 执行 ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry() 方法
  6. 执行 processConfigBeanDefinitions() – 对package下的所有Classs 进行扫描预解析成BeanDefinition
  7. parse() – 解析
  8. parse() – 解析
  9. processConfigurationClass()
  10. doProcessConfigurationClass()
protected final SourceClass doProcessConfigurationClass(
    ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
    throws IOException {
 
    // Process any @ComponentScan annotations
    // 处理 @ComponentScan 注解
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
 
    if (!componentScans.isEmpty() &&
        !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
 
        // 循环所有 @ComponentScan
        for (AnnotationAttributes componentScan : componentScans) {
            
           // 去解析,去扫描所有符合条件的 Bean 并将其包装成 ScannedGenericBeanDefinition
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            
            //  循环所有 BeanDefinitionHolder
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                // 获取原始的 BeanDefinitionHolder
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                 // 如果是NUll
                if (bdCand == null) {
                    // 将自身返回
                    bdCand = holder.getBeanDefinition();
                }
                //检测有没有  @Configuration 、@Component、@ComponentScan、@Import、@ImportResource 注解
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    //执行递归处理
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }
    return null;
}

执行扫描

也就是说是执行 componentScanParser.parse,对 @ComponentScan 注解属性的一些解读

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
 
    //创建了一个 ClassPathBeanDefinitionScanner  用于执行扫描
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(
        this.registry,
        componentScan.getBoolean("useDefaultFilters"),
        this.environment,
        this.resourceLoader);
    
    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
                                 BeanUtils.instantiateClass(generatorClass));
 
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        scanner.setScopedProxyMode(scopedProxyMode);
    } else {
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }
 
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));
 
    // 包含哪些
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addIncludeFilter(typeFilter);
        }
    }
    //排除哪些
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addExcludeFilter(typeFilter);
        }
    }
 
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }
 
    Set<String> basePackages = new LinkedHashSet<>();
    // 获取我们设置的 package
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                                                               ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    // 获取到 Class,
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        // 获取这个 Class 的 packa,也就是说这个 @componentScan.basePackageClasses 这个属性是扫描这个Class package 下内容
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    // 如果是空的.. 就默认取启动类默认的 Pakcage
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }
 
    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);
        }
    });

    //根据@componentScan 去扫描
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

扫描

根据pakcage进行扫描,

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // 存放符合条件的 BeanDefinition
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    // 循环所有Package
    for (String basePackage : basePackages) {
        // 查询 package 下的符合条件的 Class
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        //  循环所有组件
        for (BeanDefinition candidate : candidates) {
            // 解析scope属性
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            //  获取其 BeanName
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                // 处理 BeanDefinition,其实就是设置一些默认值
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                //处理注解 @Lazy、@Primary、@dependsOn
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            // 检查当前bean是否已经注册
            if (checkCandidate(beanName, candidate)) {
                //将其包装成 BeanDefinitionHolder
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 如果当前bean是用于生成代理的bean那么需要进一步处理
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // 注册到Srpign 容器中去
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

findCandidateComponents

  • 根据packa 进行扫描

scanCandidateComponents

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        // 这里根据Package 获取包下的所有 Class 文件
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        // 循环所有的 Class
        for (Resource resource : resources) {
            // 判断是否可读
            if (resource.isReadable()) {
                try {
                    // 获取其 Class 将其包装成 MetadataReader
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    // 去判断是不是 @Component、@ManagedBean、@Named 类型的注解
                    if (isCandidateComponent(metadataReader)) {
                    
                        //将其包装成  ScannedGenericBeanDefinition
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setSource(resource);
                        //判断是否是一个 可创建的类
                        if (isCandidateComponent(sbd)) {
                            //将其添加到集合中
                            candidates.add(sbd);
                        }
                    }
                } catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                        "Failed to read candidate component class: " + resource, ex);
                }
            }
        }
    } catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}

到底注册到哪里去了?

  1. 执行完 doScan() 方法后
  2. 会对其做一个处理,例如:注解解析等操作
  3. 然后包装成 BeanDefinitionHolder
  4. 最后执行 registerBeanDefinition(definitionHolder, this.registry)
  5. 执行 registerBeanDefinition()
  6. 执行 registerBeanDefinition()
  7. 最终:this.beanDefinitionMap.put(beanName, beanDefinition); 也就是说放到一个Map当中

springboot

springboot 最终也是调用大致的流程,只贴前置流程的源码

调用流程

项目启动

@SpringBootApplication
public class SpringIocApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringIocApplication.class, args);
    }
}

调用run方法

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
}
  • 内部调用 run 方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}
  • 创建对象
public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
}
public SpringApplication(
	ResourceLoader resourceLoader, 
	Class<?>... primarySources) {
		
	// 将 我们的 启动类,放到集合中 然后设置给  primarySources 这个属性
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	
}
  • 然后调用run 方法
public ConfigurableApplicationContext run(String... args) {
	prepareContext(context, environment, listeners, applicationArguments, printedBanner);
}

剩余流程

剩余流程就不贴代码了,自己可以跟一下,为啥上面贴呢,主要是将 将启动类放到 primarySources 集合中

  1. 调用 prepareContext 方法
    1. 调用 getAllSources 方法 获取 启动类集合~~
  2. 调用 load()
  3. 调用 load()
  4. 调用 load()
  5. 调用 load()
  6. 调用 annotatedReader.register(source);
  7. 循环调用 registerBean()
  8. 调用 doRegisterBean()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值