spring中扫描源码分析

193 阅读6分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第4篇文章,点击查看活动详情” 这里会将关键的源码直接贴出来,注意这里讲述的源码顺序并不是spring的一个启动流程顺序,而是针对spring源码中的扫描部分做分析解读。

1.spring源码入口: AnnotationConfigApplicationContext

创建一个spring容器,加载配置类。所以就从AnnotationConfigApplicationContext的有参构造方法来看。

public class Test {

   public static void main(String[] args)  {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
      System.out.println(context.getBean("user"));
   }
}

2.进入到 AnnotationConfigApplicationContext类的构造方法

这个有参的构造方法中: this();无参构造方法 register(componentClasses);注册 refresh();刷新

/**
 * Create a new AnnotationConfigApplicationContext, deriving bean definitions
 * from the given component classes and automatically refreshing the context.
 * @param componentClasses one or more component classes — for example,
 * {@link Configuration @Configuration} classes
 */
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   this();
   register(componentClasses);
   refresh();
}

1.进入到this()方法:

位置:AnnotationConfigApplicationContext类

public AnnotationConfigApplicationContext() {
   StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
   this.reader = new AnnotatedBeanDefinitionReader(this);
   createAnnotatedBeanDefReader.end();
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

这个方法里面的createAnnotatedBeanDefReader这个对象可以不用去看,从代码来看一个start方法,一个end方法,我猜测它的主要作用:记录一下程序的执行信息。
这里最主要的是reader和scanner,它们一个是读取,一个是扫描。

2.进入到 refresh();

这个方法很重要,比较核心的方法。扫描bean,创建bean 都是在这里面。 invokeBeanFactoryPostProcessors(beanFactory); 这个方法会调用this()方法中创建的scanner对象的scan()方法 扫描bean。
finishBeanFactoryInitialization(beanFactory); 这个方法中会实例化所有剩余的(非懒加载)单例bean。

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
      // 准备此上下文以进行刷新
      // Prepare this context for refreshing.
      prepareRefresh();
      //告诉子类刷新内部bean工厂
      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      //准备bean工厂以便在此上下文中使用
      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         //允许在上下文子类中对bean工厂进行后处理。
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

         //调用上下文中注册为bean的工厂处理器 
         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         //注册拦截bean创建的bean处理器。
         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);
         beanPostProcess.end();

         //初始化此上下文的消息源。
         // Initialize message source for this context.
         initMessageSource();
         //为此上下文初始化事件多播
         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();
         //初始化特定上下文子类中的其他特殊bean。
         // Initialize other special beans in specific context subclasses.
         onRefresh();
         //检查侦听器bean并注册它们
         // Check for listener beans and register them.
         registerListeners();
         // 实例化所有剩余的(非惰性初始化)单例。
         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);
         //最后一步:发布相应的事件。
         // Last step: publish corresponding event.
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }
         // 销毁已创建的单例以避免悬空资源
         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();
         // 重置“活动”标志。
         // Reset 'active' flag.
         cancelRefresh(ex);
         // 将异常传播到调用方。
         // Propagate exception to caller.
         throw ex;
      }

      finally {
         //重置Spring核心中的常见自省缓存,因为我们
         //可能不再需要单例bean的元数据。。。
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
         contextRefresh.end();
      }
   }
}

3.扫描

扫描主要的作用:1.将扫描得到的bean封装成beanDefinition,2将扫描得到的beanDefinition注册到容器中。
扫描用的AnnotationConfigApplicationContext类下的AnnotationConfigApplicationContext()方法中创建的scanner对象。

public AnnotationConfigApplicationContext() {
   StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
   this.reader = new AnnotatedBeanDefinitionReader(this);
   createAnnotatedBeanDefReader.end();
   this.scanner = new ClassPathBeanDefinitionScanner(this);
}

1.进入到scanner对象

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

   private final BeanDefinitionRegistry registry;

   private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();

   @Nullable
   private String[] autowireCandidatePatterns;

   private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

   private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

   private boolean includeAnnotationConfig = true;
   ......
   }

上面这段代码只是ClassPathBeanDefinitionScanner 中一部分。

1. BeanDefinitionRegistry registry;

 private final BeanDefinitionRegistry registry;

spring中的单一原则可以从这行代码中看到,或者是增强可读性。
BeanDefinitionRegistry 是一个接口,这个接口有很多实现类,其中有一个 DefaultListableBeanFactory 实现类。
DefaultListableBeanFactory 不仅实现 BeanDefinitionRegistry 接口,还实现了其他接口,所以它的功能很强大。
有意思的是,ClassPathBeanDefinitionScanner 中的 registry 属性,在实际执行中的值就是DefaultListableBeanFactory 。
那么为什么这里的registry 不直接定义为DefaultListableBeanFactory类?我猜测有以下原因
1.这个只需要注册的功能,并不需要其他功能,所以没必要定义为DefaultListableBeanFactory
2.增强可读性。从命名角度看BeanDefinitionRegistry 与DefaultListableBeanFactory 显然BeanDefinitionRegistry 可读性更强。
3.符合spring中单一原则,BeanDefinitionRegistry 主要功能就是注册,DefaultListableBeanFactory还有其他功能。

2.scan()方法中的doScan(String... basePackages)

可以在ClassPathBeanDefinitionScanner中直接搜doScan,就能找到

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
   for (String basePackage : basePackages) {
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      for (BeanDefinition candidate : candidates) {
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

1.获取BeanDefinition集合

Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

这行代码就是获取BeanDefinition,进入到findCandidateComponents()方法

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

直接进到scanCandidateComponents(basePackage)方法中

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
  Set<BeanDefinition> candidates = new LinkedHashSet<>();
  try {
     String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
           resolveBasePackage(basePackage) + '/' + this.resourcePattern;
     Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
     boolean traceEnabled = logger.isTraceEnabled();
     boolean debugEnabled = logger.isDebugEnabled();
     for (Resource resource : resources) {
        if (traceEnabled) {
           logger.trace("Scanning " + resource);
        }
        if (resource.isReadable()) {
           try {
              MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
              if (isCandidateComponent(metadataReader)) {
                 ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                 sbd.setSource(resource);
                 if (isCandidateComponent(sbd)) {
                    if (debugEnabled) {
                       logger.debug("Identified candidate component class: " + resource);
                    }
                    candidates.add(sbd);
                 }
                 ......
1.重新生成包路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
        resolveBasePackage(basePackage) + '/' + this.resourcePattern;

这行代码主要作用:根据传入的包路径获取一个适用于spring内部的包路径以方便后续使用。就是重新生成一个路径。

2.获取所有的.class文件的file对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);

根据上面生成的路径获取该路径下面的所有.class文件的file对象。

3.获取metadataReader元数据信息
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

根据resources来获取元数据信息,这个元数据信息包含了这个类的所有信息,这个地方spring用的是ASM技术来获取metadataReader。

4.根据元数据信息进行判断
if (isCandidateComponent(metadataReader)) {
1.metadataReader与(excludeFilters和includeFilters)比较匹配

根据这个类的元数据信息,进行判断,进入到这个判断逻辑里面

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   //metadataReader 和某一个排除过滤器匹配了就return false,说明它就不是一个bean
   for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return false;
      }
   }
   // metadataReader 必须有一个includeFilters 所包含的注解 才有可能是一个bean
   for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return isConditionMatch(metadataReader);
      }
   }
   return false;
}

可以看到excludeFilters和includeFilters,一个排除,一个包含。
excludeFilters(排除):metadataReader与某一个排除过滤器匹配了就return false,说明它就不是一个bean
includeFilters(包含):includeFilters在spring中会默认添加@Component注解,还有另外一个很少用(ManagedBean),也就是说,metadataReader中带有@Component注解才有可能成为bean\

2.判断是否有条件注解

可以看到下面这个下面这个判断返回的是isConditionMatch(metadataReader),进入到这个判断逻辑:

/**
 * Determine whether the given class is a candidate component based on any
 * {@code @Conditional} annotations.
 * @param metadataReader the ASM ClassReader for the class
 * @return whether the class qualifies as a candidate component
 */
private boolean isConditionMatch(MetadataReader metadataReader) {
   if (this.conditionEvaluator == null) {
      this.conditionEvaluator =
            new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
   }
   return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}

这个方法中直接进shouldSkip()方法。

public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
   return shouldSkip(metadata, null);
}

继续往下走

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
   if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
      return false;
   }

   if (phase == null) {
      if (metadata instanceof AnnotationMetadata &&
            ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
         return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
      }
      return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
   }
  ......
}

最主要看这个

if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; }

元数据信息中不包含Conditional这个注解返回false,那么就不用继续往下走逻辑判断,它才可能是一个bean。
如果包含了这个注解,那么就继续向下走逻辑:找到条件注解中的类,执行这个类的matches方法,获取方法中的结果,看是否符合条件。

5.创建beanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);

进入到这有参构造方法,

public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
   Assert.notNull(metadataReader, "MetadataReader must not be null");
   this.metadata = metadataReader.getAnnotationMetadata();
   setBeanClassName(this.metadata.getClassName());
   setResource(metadataReader.getResource());
}

可以看到有setBeanClassName,这个地方赋值的只是名字,

/**
 * 指定此bean定义的bean类名
 * Specify the bean class name of this bean definition.
 */
@Override
public void setBeanClassName(@Nullable String beanClassName) {
   this.beanClass = beanClassName;
}

进去之后可以看到注释:指定此bean定义的bean类名。然而这个this.beanClass 的类型是Object,不是String类型。基于现在的流程来看,现在只是获取一些元数据信息,并没有加载类,所以是拿不到clazz对象的。当需要用到与此类名相同的类的时候就会去加载,获取clazz对象,并赋值给beanClass属性。

6.再判断beanDefinition是否符合候选条件
if (isCandidateComponent(sbd)) {

进入到该方法

/**
*确定给定的bean定义是否符合候选条件。
* 默认实现检查类是否为接口
*且不依赖于外围类。
* 可以在子类中重写。要检查的bean定义
* @返回bean定义是否有资格作为候选组件
* /
/**
 * Determine whether the given bean definition qualifies as candidate.
 * <p>The default implementation checks whether the class is not an interface
 * and not dependent on an enclosing class.
 * <p>Can be overridden in subclasses.
 * @param beanDefinition the bean definition to check
 * @return whether the bean definition qualifies as a candidate component
 */
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
   AnnotationMetadata metadata = beanDefinition.getMetadata();
   return (metadata.isIndependent() && (metadata.isConcrete() ||
         (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}

这个方法就是判断给定的bean定义是否符合候选条件,满足这些条件才会将beanDefinition添加到集合中。 metadata.isIndependent():必须是顶级类,不依赖外部类 metadata.isConcrete():不能是接口和抽象类 metadata.isAbstract():如果抽象类的情况下,且该抽象类的方法上包含Lookup注解(metadata.hasAnnotatedMethods(Lookup.class.getName()))也符合条件

2.获取scope注解的信息

ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());

主要是获取scope值并赋值candidate.setScope;

3.获取beanName

String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

进入到generateBeanName()方法中,位置:AnnotationBeanNameGenerator

public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
   if (definition instanceof AnnotatedBeanDefinition) {
      String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
      if (StringUtils.hasText(beanName)) {
         // Explicit bean name found.
         return beanName;
      }
   }
   // Fallback: generate a unique default bean name.
   return buildDefaultBeanName(definition, registry);
}

上面这个段代码: if判断中获取的是@Component中的值,如果@Component没有指定值,那么就会返回这个方法:

buildDefaultBeanName(definition, registry)。

生成的默认值.

4.给beanDefinition赋默认值

postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);

5.解析类上面的注解

这个方法中会解析这些注解:@Lazy @Primary @DependsOn等

AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);

6.判断beanDefinition是否存在

if (checkCandidate(beanName, candidate)) {

进入到这个方法中checkCandidate()

protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
   if (!this.registry.containsBeanDefinition(beanName)) {
      return true;
   }
   BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
   BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
   if (originatingDef != null) {
      existingDef = originatingDef;
   }
   if (isCompatible(beanDefinition, existingDef)) {
      return false;
   }
   throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
         "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
         "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}

这段代码:

if (!this.registry.containsBeanDefinition(beanName)) {
  return true;
  }

这个registry就是ClassPathBeanDefinitionScanner的registry属性,就是这个

private final BeanDefinitionRegistry registry;

前面有说的这个属性在执行的时候真正的值是:DefaultListableBeanFactory类型的值,那么进入到DefaultListableBeanFactory中这个方法containsBeanDefinition(String beanName)

@Override
public boolean containsBeanDefinition(String beanName) {
   Assert.notNull(beanName, "Bean name must not be null");
   return this.beanDefinitionMap.containsKey(beanName);
}

可以看到这个地方就是一个beanDefinitionMap。
所以可以得出,如果这个beanDefinitionMap中已经存在是不会在存进去的。要么抛异常,要么不会注册。

7.创建BeanDefinitionHolder

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);

8.注册BeanDefinition

1
registerBeanDefinition(definitionHolder, this.registry);
2
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
3
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

这个三块代码,registerBeanDefinition(definitionHolder, this.registry)中传入的是ClassPathBeanDefinitionScanner中的registry属性,那么在第3块代码中registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());使用的就是 DefaultListableBeanFactory类下的registerBeanDefinition方法。 进入到这个方法(DefaultListableBeanFactory的registerBeanDefinition方法)中可以看到

this.beanDefinitionMap.put(beanName, beanDefinition);

是将 beanName和beanDefinition 放到了beanDefinitionMap中。

到此spring的扫描逻辑基本是完成了。