Spring全家桶源码解析--2.1 Spring bean 的创建--包的扫描

文章目录

  • 前言
  • 一、ComponentScan 扫描路径定义:
  • 二、包路径扫描:
    • 2.1 AnnotationConfigApplicationContext:
      • 2.1.1 reader 和 scan 初始化:
    • 2.2 包扫描:
      • 2.2.1 scan 扫描:
      • 2.2.2 doScan 扫描:
      • 2.2.3 findCandidateComponents 获取BeanDefinition :
  • 三、扩展:
    • 3.1 条件Condition :
    • 3.2 Lookup 注解 :
  • 总结


前言

Spring 中通过不同的bean 负责不同的功能,那么spring 在加载的时候,怎么知道哪些类需要去生成bean?


一、ComponentScan 扫描路径定义:

在spring 的启动类中可以添加 @ComponentScan 并且 定义扫描的bean路径,从而在spring 启动的时候,可以知晓从哪些地方的类需要去生成bean 。

@ComponentScan(basePackages = "com.xxxx")

main

public static void main(String[] args) {
   ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
   context.getBean("xxxx");
}

二、包路径扫描:

2.1 AnnotationConfigApplicationContext:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();  // reader 和 scan 初始化
    this.register(componentClasses);
    this.refresh();// bean 的生成
}

2.1.1 reader 和 scan 初始化:

 public AnnotationConfigApplicationContext() {
   StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
   	 // 定义BeanDefinitionReader
     this.reader = new AnnotatedBeanDefinitionReader(this);
     createAnnotatedBeanDefReader.end();
      // 定义BeanDefinitionScanner 这里会把 Component.class 注解类默认放入到 includeFilters的 TypeFilter中
     this.scanner = new ClassPathBeanDefinitionScanner(this);
 }

2.2 包扫描:

通过 ClassPathBeanDefinitionScanner scan 方法,为每个要生成bean 的类 生成BeanDefinition,后面在创建bean 的时候可以从中获取类的注解,属性 ,方法等。

2.2.1 scan 扫描:

 public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    this.doScan(basePackages);// 做扫描工作
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }
	// 返回本次扫描了多少个BeanDefinition
    return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}

2.2.2 doScan 扫描:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
    String[] var3 = basePackages;
    int var4 = basePackages.length;
	// 遍历每个包路径
    for(int var5 = 0; var5 < var4; ++var5) {
        String basePackage = var3[var5];
         // 遍历获取每个路径下的 BeanDefinition 
        Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
        Iterator var8 = candidates.iterator();

        while(var8.hasNext()) {
            BeanDefinition candidate = (BeanDefinition)var8.next();
			// 获取 这个类的 scope 
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
			// 获取 这个类的 bean 名称  如果 @Component  中定义了value 值则获取改制 否则按照默认的规则生成bean name
			// 即 类的第一个字母小写.但是如果 类的名字第一个和
			// 第二个字母都是大写,则直接使用,生成的bean 的首字母和第二个字母都是大写
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
				//   BeanDefinition 赋值默认值(是否懒加载等)
                this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
            }

            if (candidate instanceof AnnotatedBeanDefinition) {
                //  处理 @Lazy  @Primary,@DependsOn @Role @Description等注解
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
            }
			// 如果改bean 的 BeanDefinition 已经存在大部分会抛异常出来
            if (this.checkCandidate(beanName, candidate)) {
               // 检查spring 中是否已经有改beanName 如果没有存在则进行注册
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
               // 注册最终放入到 DefaultListableBeanFactory 的 Map beanDefinitionMap; 中
                this.registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }

    return beanDefinitions;
}

2.2.3 findCandidateComponents 获取BeanDefinition :

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    return this.componentsIndex != null && this.indexSupportsIncludeFilters() ? this.addCandidateComponentsFromIndex(this.componentsIndex, basePackage) : this.scanCandidateComponents(basePackage);
}

scanCandidateComponents: 扫描 @Component

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	// BeanDefinition set 集合将扫描到有 @Component 注解标注并且符合条件的包装成BeanDefinition 
    Set<BeanDefinition> candidates = new LinkedHashSet();

    try {
		// 定义class 的资源路径
        String packageSearchPath = "classpath*:" + this.resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		// 获取包路径下的 file 资源
        Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath);
        boolean traceEnabled = this.logger.isTraceEnabled();
        boolean debugEnabled = this.logger.isDebugEnabled();
        Resource[] var7 = resources;
        int var8 = resources.length;

        for(int var9 = 0; var9 < var8; ++var9) {
        	// 获取到每个file 资源
            Resource resource = var7[var9];
            if (traceEnabled) {
                this.logger.trace("Scanning " + resource);
            }

            try {
				// 获取改资源的 类元数据信息 (注解,属性,方法等)
                MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);
                if (this.isCandidateComponent(metadataReader)) {
					// 符合生成bean 的条件,构造BeanDefinition
                    ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                    sbd.setSource(resource);
                    if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
                        if (debugEnabled) {
                            this.logger.debug("Identified candidate component class: " + resource);
                        }
						// 加入 bean定义的set 集合
                        candidates.add(sbd);
                    } else if (debugEnabled) {
                        this.logger.debug("Ignored because not a concrete top-level class: " + resource);
                    }
                } else if (traceEnabled) {
                    this.logger.trace("Ignored because not matching any filter: " + resource);
                }
            } catch (FileNotFoundException var13) {
                if (traceEnabled) {
                    this.logger.trace("Ignored non-readable " + resource + ": " + var13.getMessage());
                }
            } catch (Throwable var14) {
                throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var14);
            }
        }

        return candidates;
    } catch (IOException var15) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var15);
    }
}

isCandidateComponent 是否符合bean 的条件: 这个类不是内部类,也不是接口 ,或者改类是抽象类但是没有定义 Lookup 则可以满足生成bean 的条件

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    // 如果 类中定义 了排除 ,则进行匹配,如果该类在排除的范围之内则直接返回false
Iterator var2 = this.excludeFilters.iterator();

    TypeFilter tf;
    do {
        if (!var2.hasNext()) {
           // 如果没有被排除则,查看是否在 包含 filter 之内,如果都不包含也返回false
           // 在容器准备阶段已经定义了一个 默认的 的includeFilter ,它就是 @Component
            var2 = this.includeFilters.iterator();

            do {
                if (!var2.hasNext()) {
                    return false;
                }

                tf = (TypeFilter)var2.next();
            } while(!tf.match(metadataReader, this.getMetadataReaderFactory()));
            // 类中有@Component 注解,在进行条件匹配
            return this.isConditionMatch(metadataReader);
        }

        tf = (TypeFilter)var2.next();
    } while(!tf.match(metadataReader, this.getMetadataReaderFactory()));

    return false;
}

是否条件匹配 isConditionMatch:得到true 则意味这个类需要生成baen, 得到false 则不需要生成bean

this.isConditionMatch(metadataReader);
private boolean isConditionMatch(MetadataReader metadataReader) {
    if (this.conditionEvaluator == null) {
        this.conditionEvaluator = new ConditionEvaluator(this.getRegistry(), this.environment, this.resourcePatternResolver);
    }

    return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationCondition.ConfigurationPhase phase) {
    if (metadata != null && metadata.isAnnotated(Conditional.class.getName())) {
        if (phase == null) {
            return metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata)metadata) ? this.shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION) : this.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
        } else {
			// 调用业务本身,改类 实现了Condition 接口 的matches 方法,如果得到true 则意味这个类需要生成baen
			// 得到false  则不需要生成bean
            List<Condition> conditions = new ArrayList();
            Iterator var4 = this.getConditionClasses(metadata).iterator();

            while(var4.hasNext()) {
                String[] conditionClasses = (String[])var4.next();
                String[] var6 = conditionClasses;
                int var7 = conditionClasses.length;

                for(int var8 = 0; var8 < var7; ++var8) {
                    String conditionClass = var6[var8];
                    Condition condition = this.getCondition(conditionClass, this.context.getClassLoader());
                    conditions.add(condition);
                }
            }

            AnnotationAwareOrderComparator.sort(conditions);
            var4 = conditions.iterator();

            Condition condition;
            ConfigurationCondition.ConfigurationPhase requiredPhase;
            do {
                do {
                    if (!var4.hasNext()) {
                        return false;
                    }

                    condition = (Condition)var4.next();
                    requiredPhase = null;
                    if (condition instanceof ConfigurationCondition) {
                        requiredPhase = ((ConfigurationCondition)condition).getConfigurationPhase();
                    }
                } while(requiredPhase != null && requiredPhase != phase);
            } while(condition.matches(this.context, metadata));

            return true;
        }
    } else {
		// 类上没有条件注解则直接 返回false ,意味着 这个类需要生成bean
        return false;
    }
}

三、扩展:

3.1 条件Condition :

Spring中的Condition接口是用于在runtime时决定一个bean或者某配置是否需要被创建或加载的。你可以使用@Conditional注解,并实现Condition接口,然后通过Condition#matches()方法来定义条件。

例如:

public class OnSystemPropertyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return.getProperty("my.property") != null;
    }
}

在此例中,如果系统属性"my.property"存在,那么条件就满足,否则条件不满足。

然后你可以使用@Conditional注解来利用这个Condition:


@Configuration
@Conditional(OnSystemPropertyCondition.class)
public class ConditionConfig {
    // some beans definitions...
}

在上面的例子中,只有当"my.property"系统属性存在时,ConditionConfig的定义和它下面的Bean才会被创建和注册到Spring的ApplicationContext中。

Condition提供了很好的方式来控制Bean的创建和配置的加载,使其可以适应不同的环境和条件。

3.2 Lookup 注解 :

Spring的@Lookup注解是用来覆盖在Spring IoC容器中单例Bean的某些方法,使它们每次被调用时都返回一个新的原型Bean(prototype bean)实例。

在某些情况下,可能需要在一个单例Bean中维护一些原型Bean的引用。但是,因为单例Bean在器启动时只被创建一次,它所持有的原型Bean也只会在那时创建一次。这可能会导致问题,因为通常我们期望每次请求原型Bean时,容器都能提供一个新的实例。

这时,我们就可以使用@Lookup注解来解决这个问题。@Lookup注解让我们可以定义一个返回特定类型的方法,并在需要时覆盖这个方法,使得每次调用这个方法时容器都会返回一个新的Bean实例。

@Service
public abstract class SingletonService {

    // ...

    @Lookup
    public abstract PrototypeBean createPrototypeBean();

    public void doSomething() {
        PrototypeBean prototypeBean = createPrototypeBean();
        // 处理prototypeBean
    }
}

在上面的例子中,SingletonService是一个单例Bean,其中定义了一个用@Lookup注解标注的方法createPrototypeBean。每次调用这个方法,Spring都会为我们返回一个新的PrototypeBean实例。

总结

spring 通过sanner 对其传入的包路径进行扫描,遍历每个路径,获取其路径下的所以file 资源,筛选出有@Component 标注 并且非接接口 非抽象类,没有条件注解(或者条件注解返回true)的类,为其设置name ,填充socpe,lazy,Primary,DependsOn,Description 等属性包装生成BeanDefinition 最终放入到beanDefinitionMap ,供后面生成bean使用。

你可能感兴趣的:(Spring框架篇,源码解析篇,spring,java)