Springboot源码分析第一弹 - 自动装配实现

544 阅读10分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Springboot就不用多了吧,解放Java开发双手的神器。 最显著的特点就是,去配置化,自动装配,自动配置。让开发人员只需要注重业务的开发 今天就来了解一下自动装配的源码是怎么实现的

预先准备

  • 直接引用springboot包2.5.6的
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.6</version>
</parent>
  • 再贴一下以前的MVC扫描包的web.xml配置
<!-- 一般applicationContext里面会有扫描包路径配置 -->
<context:component-scan base-package="com.demo.xxx"></context:component-scan>

以前是有入口指定扫描路径,但是springboot又没有这个配置,确也能扫描出来是怎么实现的,来一探究竟吧!

流程概括

  1. 入口肯定是run方法,参数传入的是当前的启动类
  2. 在容器初始化之前传入的启动类注册到容器中去,然后再刷新容器refresh()
  3. 在容器注册阶段完成后,就是将所有的需要加载类注册到BeanDefinitionMap了
  4. 然后在上下文中调用注册bean的处理器回调,在springboot包中解析bean
  5. 关注点在注册类,解析该类时得到扫描路径即当前路径 ‘.’ ,也就说明了springboot项目默认扫描到启动类那一层,扫描我们手写的代码后注册到容器,但是所需依赖还是没有想容器注册的
  6. 启动类上有@Import注解,解析时会一并处理,然后获取import的类的回调来获取需要自动装配的类
  7. 在回调类中解析需要自动装载的类,通过读取包内文件目录下META-INF/spring.factories的配置中获取对应key的值
  8. 最终想容器注册,自动装配流程到此完结

源码分析

上面流程中可以分为三步,一步一步分析。

1.向容器注册启动类

  • 入口就是run()方法,直接到源码中去
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args){
 //primarySource 启动类
 return run(new Class<?>[] { primarySource }, args);
}
  • 接下来run一直往下到SpringApplication#run()
public ConfigurableApplicationContext run(String... args) {
 StopWatch stopWatch = new StopWatch();
 stopWatch.start();
 DefaultBootstrapContext bootstrapContext = createBootstrapContext();
 ConfigurableApplicationContext context = null;
 configureHeadlessProperty();
 //获取需要注册的监听
 SpringApplicationRunListeners listeners = getRunListeners(args);
 listeners.starting(bootstrapContext, this.mainApplicationClass);
 try {
  ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  //环境和配置 后面会讲到
  ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  configureIgnoreBeanInfo(environment);
  //打印启动banner
  Banner printedBanner = printBanner(environment);
  //创建web容器
  context = createApplicationContext();
  //设置web容器的启动类 DefaultApplicationStartup
  context.setApplicationStartup(this.applicationStartup);
  //为容器初始化之前做一些准备 ### 我们主要先看这里
  prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  //初始容器
  refreshContext(context);
  //初始化完成
  afterRefresh(context, applicationArguments);
  stopWatch.stop();
  if (this.logStartupInfo) {
   new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  }
  //容器创建完成的通知
  listeners.started(context);
  //回调callRuners 即实现了CommandLineRunner接口的回调
  callRunners(context, applicationArguments);
 }catch (Throwable ex) {
  handleRunFailure(context, ex, listeners);
  throw new IllegalStateException(ex);
 }
 try {
  //容器已启动的通知
  listeners.running(context);
 }catch (Throwable ex) {
  handleRunFailure(context, ex, null);
  throw new IllegalStateException(ex);
 }
 return context;
}
  • 先看容器加载前的处理
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
 SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    //容器的一些设置
 context.setEnvironment(environment);
 postProcessApplicationContext(context);
 applyInitializers(context);
 listeners.contextPrepared(context);
 if (this.logStartupInfo) {
  logStartupInfo(context.getParent() == null);
  logStartupProfileInfo(context);
 }
 // Add boot specific singleton beans
    //向容器注册一些单列bean
 ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
 beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
 if (printedBanner != null) {
  beanFactory.registerSingleton("springBootBanner", printedBanner);
 }
 if (beanFactory instanceof DefaultListableBeanFactory) {
  ((DefaultListableBeanFactory) beanFactory)
    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
 }
 if (this.lazyInitialization) {
  context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
 }
 // Load the sources
    //这块是重点 getAllSources()里返回的是run方法里面传入的xxx.class,其实就是启动类
 Set<Object> sources = getAllSources();
 Assert.notEmpty(sources, "Sources must not be empty");
    //从上面得知这里传入的sources其实就是启动类 接下来看这里是怎么加载的 ###
 load(context, sources.toArray(new Object[0]));
 listeners.contextLoaded(context);
}
  • 这里拿到的是启动类,那么load的就是class,一直往下到BeanDefinitionLoader#load(Class<?> source)
private void load(Class<?> source) {
 if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
  // Any GroovyLoaders added in beans{} DSL can contribute beans here
  GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
  ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
 }
 //return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
 //不是空的类 不是Groovy闭包 也不是匿名类 就直接向容器注册
 if (isEligible(source)) {
  //也就是说先将
  this.annotatedReader.register(source);
 }
}

//this.annotatedReader.register(source)接下来 会注册到IOC容器中去
AnnotatedBeanDefinitionReader
-> registerBean(componentClass)
-> doRegisterBean
-> BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

到这里第一个点就完成,本意就是把启动类注册到容器中去,然后在上下文中回调中用大到该类完成扫描业务代码,因为没有地方配置让spring扫描哪些包名下的类,类似完成web.xml中的component-scan配置

2.向容器注册业务类

  • 接下来回到最开始的SpringApplication#run,找到以下代码
//容器刷新前
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//重点看这个 刷新容器  ###
refreshContext(context);
//一直往下 接下来到这里
protected void refresh(ApplicationContext applicationContext) {
 Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
 ((AbstractApplicationContext) applicationContext).refresh();
}
//接下来又到 AbstractApplicationContext.refresh() IOC名场面了
//多的就不说了 直接看这个
// Invoke factory processors registered as beans in the context.
// 在上下文中调用注册为bean的工厂处理器 就是回调
invokeBeanFactoryPostProcessors(beanFactory);

//往下到这里
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  • 接下来到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(),只贴关键代码
public static void invokeBeanFactoryPostProcessors(
 ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

 // Invoke BeanDefinitionRegistryPostProcessors first, if any.
 Set<String> processedBeans = new HashSet<>();

 if (beanFactory instanceof BeanDefinitionRegistry) {
   //省略部分代码
           ......
  // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        //调用实现类   
        //这里还要注意一下 断点调试spring包实现了这个类的只有一个      
        //就是ConfigurationClassPostProcessor  
  String[] postProcessorNames =
  beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  for (String ppName : postProcessorNames) {
   if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                 //添加到列表
    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    processedBeans.add(ppName);
   }
  }
  sortPostProcessors(currentRegistryProcessors, beanFactory);
  registryProcessors.addAll(currentRegistryProcessors);
        //针对于注册的bean进行回调 接下来看这里  ###
  invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
  
 //省略部分代码
 ......
}

//invokeBeanDefinitionRegistryPostProcessors
private static void invokeBeanDefinitionRegistryPostProcessors(
  Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

 for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
  StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
    .tag("postProcessor", postProcessor::toString);
  //开始对实现了BeanDefinitionRegistryPostProcessor接口的bean进行回调  
  postProcessor.postProcessBeanDefinitionRegistry(registry);
  postProcessBeanDefRegistry.end();
 }
}
  • 经过断点调试,会到spring-context-5.3.12.jar包下的ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
  • 需要注意的一个点,前面已经说到手动注册了启动类,那么candidateNames里面肯定会有启动类。其他的类我们忽略,主要看启动类的扫描和加载
//一直往下到这里
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
 List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
 String[] candidateNames = registry.getBeanDefinitionNames();

 for (String beanName : candidateNames) {
  BeanDefinition beanDef = registry.getBeanDefinition(beanName);
  if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
   if (logger.isDebugEnabled()) {
    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
   }
  }
        //判断是否加了 @Configuration 这个注解
  else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            //满足就加到list中 这里的启动类肯定是加了这个注解的 可以自己进行验证
   configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
  }
 }
  
     //省略部分代码
        ......
 // Parse each @Configuration class
 ConfigurationClassParser parser = new ConfigurationClassParser(
   this.metadataReaderFactory, this.problemReporter, this.environment,
   this.resourceLoader, this.componentScanBeanNameGenerator, registry);

 Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
 Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 do {
        //开始解析带有@Configuration注解的类 ###先看这个
  parser.parse(candidates);
  parser.validate();
  //得到解析出来需要加载的类
  Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
  configClasses.removeAll(alreadyParsed);

  // Read the model and create bean definitions based on its content
  if (this.reader == null) {
   this.reader = new ConfigurationClassBeanDefinitionReader(
     registry, this.sourceExtractor, this.resourceLoader, this.environment,
     this.importBeanNameGenerator, parser.getImportRegistry());
  }
  //把需要加载的类注册到容器中去
  this.reader.loadBeanDefinitions(configClasses);
  alreadyParsed.addAll(configClasses);

 //省略部分代码
        ......
}
  • 先看下parser.parse(candidates);做了什么,到ConfigurationClassParser#parse()
ublic void parse(Set<BeanDefinitionHolder> configCandidates) {
 for (BeanDefinitionHolder holder : configCandidates) {
  BeanDefinition bd = holder.getBeanDefinition();
  try {
               //启动类注解了@Configuration 属于注解annotation definition
   if (bd instanceof AnnotatedBeanDefinition) {
                //接下来走这里 ##
    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
   }
   else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
    parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
   }
   else {
    parse(bd.getBeanClassName(), holder.getBeanName());
   }
  }
  catch (BeanDefinitionStoreException ex) {
   throw ex;
  }
  catch (Throwable ex) {
   throw new BeanDefinitionStoreException(
     "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
  }
 }
 //分析完parse后 在来分析这个process
 this.deferredImportSelectorHandler.process();
}
  • 一直往下到真正干活的类,ConfigurationClassParser#doProcessConfigurationClass 解析核心类
protected final SourceClass doProcessConfigurationClass(
 ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
 throws IOException {
 //解析 @Component 注解
 if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
  // Recursively process any member (nested) classes first
  processMemberClasses(configClass, sourceClass, filter);
 }

 //@PropertySource注解
 // Process any @PropertySource annotations
 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
   sourceClass.getMetadata(), PropertySources.class,
   org.springframework.context.annotation.PropertySource.class)) {
  if (this.environment instanceof ConfigurableEnvironment) {
   processPropertySource(propertySource);
  }
  else {
   logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
     "]. Reason: Environment must implement ConfigurableEnvironment");
  }
 }

 //@ComponentScan注解 扫描对应的包路径
 //@SpringBootApplication上面有该注解,也可以自己指定
 // Process any @ComponentScan annotations
 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
   sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
 if (!componentScans.isEmpty() &&
   !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
  for (AnnotationAttributes componentScan : componentScans) {
   // The config class is annotated with @ComponentScan -> perform the scan immediately
   //查找ComponentScan注解是否有使用value
   //接下来先看看怎么扫描的 ####
   Set<BeanDefinitionHolder> scannedBeanDefinitions =
     this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
   // Check the set of scanned definitions for any further config classes and parse recursively if needed
   for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
    BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
    if (bdCand == null) {
     bdCand = holder.getBeanDefinition();
    }
    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
     parse(bdCand.getBeanClassName(), holder.getBeanName());
    }
   }
  }
 }
 //@Import注解 先分析完扫描 下一步再重点看这里 ###
 // Process any @Import annotations
 processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
 //@ImportResource 注解
 // Process any @ImportResource annotations
 AnnotationAttributes importResource =
   AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
 if (importResource != null) {
  String[] resources = importResource.getStringArray("locations");
  Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
  for (String resource : resources) {
   String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
   configClass.addImportedResource(resolvedResource, readerClass);
  }
 }
 //@Bean 注解的方法
 // Process individual @Bean methods
 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
 for (MethodMetadata methodMetadata : beanMethods) {
  configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
 }

 // Process default methods on interfaces
 processInterfaces(configClass, sourceClass);

 // Process superclass, if any
 if (sourceClass.getMetadata().hasSuperClass()) {
  String superclass = sourceClass.getMetadata().getSuperClassName();
  if (superclass != null && !superclass.startsWith("java") &&
    !this.knownSuperclasses.containsKey(superclass)) {
   this.knownSuperclasses.put(superclass, configClass);
   // Superclass found, return its annotation metadata and recurse
   return sourceClass.getSuperClass();
  }
 }

 // No superclass -> processing is complete
 return null;
}
  • @ComponentScan 指定扫描包路径,ConfigurationClassParser#doProcessConfigurationClass
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
-> ComponentScanAnnotationParser.parse

//到这个方法
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
 //省略部分代码
 ......

 Set<String> basePackages = new LinkedHashSet<>();
 //获取手动写的扫描包路径  就是注解里面写的包路径
 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);
 }
 for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
  basePackages.add(ClassUtils.getPackageName(clazz));
 }
 //这里我们没有手动写扫描路径 所以会走这里
 if (basePackages.isEmpty()) {
  //接下来看这里
  //public static String getPackageName(String fqClassName) {
           //Assert.notNull(fqClassName, "Class name must not be null");
           //int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
           //return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
           //}
  // 然后发现了 private static final char PACKAGE_SEPARATOR = '.';
  //那么拿到的就是启动类的包名路径,这也验证了springboot 项目默认扫描到启动类那一层
  basePackages.add(ClassUtils.getPackageName(declaringClass));
 }

 scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
  @Override
  protected boolean matchClassName(String className) {
   return declaringClass.equals(className);
  }
 });
 //扫描指定包路径下的类文件 接下来我看继续往下看 ###
 return scanner.doScan(StringUtils.toStringArray(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) {
    //回调 因为此时容器已经处理回调这一步 所以新注册的bean需要自己回调
    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;
}
  • 接下来到ClassPathScanningCandidateComponentProvider#findCandidateComponents -> scanCandidateComponents
//这不就是混熟悉的读流了
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
 Set<BeanDefinition> candidates = new LinkedHashSet<>();
 try {
  //resourcePattern = **/*.class class后缀
  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);
   }
   try {
    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
    //满足注解的 @Component  其实所有需要加载的注解 都实现了@Component
    if (isCandidateComponent(metadataReader)) {
     ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
     sbd.setSource(resource);
     if (isCandidateComponent(sbd)) {
      if (debugEnabled) {
       logger.debug("Identified candidate component class: " + resource);
      }
      //把对应路径下的class文件扫描到list中 然后向容器中注册
      candidates.add(sbd);
     }
     .... //省略部分代码
 return candidates;
}

到这里为止,已经把我们自己写的业务代码注册到容器中了,但是springboot框架需要依赖的bean还是没有注册的,接下来看下自动装配怎么实现的吧

3.向容器注册所需依赖的自动装配的类

  • 我们回到ConfigurationClassParser.doProcessConfigurationClass方法中
//找到这行对 @import注解的解析
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

//接下来到processImports这个方法里面  找到这一部分 只有加了@Import注解的才会进来
for (SourceClass candidate : importCandidates) {
 if (candidate.isAssignable(ImportSelector.class)) {
  // Candidate class is an ImportSelector -> delegate to it to determine imports
  Class<?> candidateClass = candidate.loadClass();
  ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
    this.environment, this.resourceLoader, this.registry);
  Predicate<String> selectorFilter = selector.getExclusionFilter();
  if (selectorFilter != null) {
   exclusionFilter = exclusionFilter.or(selectorFilter);
  }
         //这里只有是DeferredImportSelector的实现才走这里
         //所以找启动类上的注解,只有@EnableAutoConfiguration里面有引入
         //@Import(AutoConfigurationImportSelector.class)
         //DeferredImportSelector 继承了 ImportSelector
  if (selector instanceof DeferredImportSelector) {
            //接下来走这里 ###
   this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
  }
  else {
   String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
   Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
   processImports(configClass, currentSourceClass, importSourceClasses, false);
  }
 }
 ...//省略部分代码
 
}

  • 接下来到ConfigurationClassParser#handler方法,到内部类DeferredImportSelectorHandler
//贴一下该类的两个方法
private class DeferredImportSelectorHandler {

 @Nullable
 private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

 public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
  DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
  //只有在process 也就是处理中的时候为null 本地变量锁的用法
  if (this.deferredImportSelectors == null) {
   DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
   handler.register(holder);
   //递归
   handler.processGroupImports();
  }
  else {
   //正常不会为null 添加到这个list
   this.deferredImportSelectors.add(holder);
  }
 }

 public void process() {
  List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
  this.deferredImportSelectors = null;
  try {
   if (deferredImports != null) {
    DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
    deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
    deferredImports.forEach(handler::register);
    //根据已添加的ImportSelector的类进行回调 接下来走这里 ###
    handler.processGroupImports();
   }
  }
  finally {
   this.deferredImportSelectors = new ArrayList<>();
  }
 }
}

上面通过解析已经拿到所有用@Import引入并且实现了DeferredImportSelector的类集合

  • 再次回到ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)
//找到该该方法的最后一行代码
this.deferredImportSelectorHandler.process();
//到上面内部类DeferredImportSelectorHandler#process,接下来走这行代码
handler.processGroupImports();

public void processGroupImports() {
 for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
  Predicate<String> exclusionFilter = grouping.getCandidateFilter();
  //先看getImports() ###
  grouping.getImports().forEach(entry -> {
   ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
   try {
    //这里又是处理import注解的方法,但是走的判断不一样
    processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
      Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
      exclusionFilter, false);
   }
   catch (BeanDefinitionStoreException ex) {
    throw ex;
   }
   catch (Throwable ex) {
    throw new BeanDefinitionStoreException(
      "Failed to process import candidates for configuration class [" +
        configurationClass.getMetadata().getClassName() + "]", ex);
   }
  });
 }
}
  • ConfigurationClassParser#getImports()
public Iterable<Group.Entry> getImports() {
 for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
  //获取需要自动加载的类 ###  
  this.group.process(deferredImport.getConfigurationClass().getMetadata(),
  deferredImport.getImportSelector());
 }
 //经过处理后 返回所需的自动装置的类
 return this.group.selectImports();
}
  • 这个group会到AutoConfigurationImportSelector的内部类AutoConfigurationGroup#process
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
 Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
   () -> String.format("Only %s implementations are supported, got %s",
     AutoConfigurationImportSelector.class.getSimpleName(),
     deferredImportSelector.getClass().getName()));
 //解析需要自动装配的类  接下来看怎么找到需要解析的类 ###     
 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
   .getAutoConfigurationEntry(annotationMetadata);
 //保存 在下面的selectImports 进行处理后返回  
 this.autoConfigurationEntries.add(autoConfigurationEntry);
 for (String importClassName : autoConfigurationEntry.getConfigurations()) {
  this.entries.putIfAbsent(importClassName, annotationMetadata);
 }
}
 
 //获取到自动装配的类的后续 等下就不贴了
 @Override
 public Iterable<Entry> selectImports() {
  if (this.autoConfigurationEntries.isEmpty()) {
   return Collections.emptyList();
  }
  //需要排除的classname
  Set<String> allExclusions = this.autoConfigurationEntries.stream()
    .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
     //需要自动装配的classname的list集合
  Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
    .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
    .collect(Collectors.toCollection(LinkedHashSet::new));
  //移除  
  processedConfigurations.removeAll(allExclusions);
  //排序并封装
  return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
    .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
    .collect(Collectors.toList());
 }
}
//getgetAutoConfigurationEntry -> getCandidateConfigurations
//到AutoConfigurationImportSelector
//通过classLoader获取指定key需要自动装配的类
List<String> configurations = 
//getSpringFactoriesLoaderFactoryClass return EnableAutoConfiguration.class;
//这里的key也就是自动装配EnableAutoConfiguration类路径
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
  getBeanClassLoader()); 


public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
 ClassLoader classLoaderToUse = classLoader;
 if (classLoaderToUse == null) {
  classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
 }
 //key明就是EnableAutoConfiguration类路径
 //org.springframework.boot.autoconfigure.EnableAutoConfiguration
 String factoryTypeName = factoryType.getName();
 //这里从缓存中获取对应类加载器的自动装配的内容 然后再取出key的值 默认返回空list
 return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

  • 接下来SpringFactoriesLoader #loadSpringFactories,获取所有需要自动装置的类存入缓存

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
 //先从缓存获取
 Map<String, List<String>> result = cache.get(classLoader);
 if (result != null) {
  return result;
 }

 result = new HashMap<>();
 try {
  //String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
        //从路径得知应该是去指定文件里面读取 接下来我们看下对应的文件
  Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
  while (urls.hasMoreElements()) {
   URL url = urls.nextElement();
   UrlResource resource = new UrlResource(url);
   Properties properties = PropertiesLoaderUtils.loadProperties(resource);
   for (Map.Entry<?, ?> entry : properties.entrySet()) {
    String factoryTypeName = ((String) entry.getKey()).trim();
    String[] factoryImplementationNames =
      StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
    for (String factoryImplementationName : factoryImplementationNames) {
     result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
       .add(factoryImplementationName.trim());
    }
   }
  }

  // Replace all lists with unmodifiable lists containing unique elements
  result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
    .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
  //保存到对应类加载器的map key是对应的类加载器  
  cache.put(classLoader, result);
 }
 catch (IOException ex) {
  throw new IllegalArgumentException("Unable to load factories from location [" +
    FACTORIES_RESOURCE_LOCATION + "]", ex);
 }
 return result;
}
  • 这里只引人了springboot包,所以找一下spring-boot-autoconfigure包目录下的META-INF/spring.factories的文件,找到对应的key
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
......
  • 反正对应需要自动装配的类之后,接下来回到ConfigurationClassParser#processGroupImports
public void processGroupImports() {
 for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
  Predicate<String> exclusionFilter = grouping.getCandidateFilter();
  grouping.getImports().forEach(entry -> {
   ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
   try {
    //会继续走到扫描加载类 递归的做法 ###
    processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
      Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
      exclusionFilter, false);
   }
   catch (BeanDefinitionStoreException ex) {
    throw ex;
   }
   catch (Throwable ex) {
    throw new BeanDefinitionStoreException(
      "Failed to process import candidates for configuration class [" +
        configurationClass.getMetadata().getClassName() + "]", ex);
   }
  });
 }
}
  • 接下来回到ConfigurationClassParser#processImports,因为此时已经不是ImportSelector,找到这个else
else {
 // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
 // process it as an @Configuration class
 //不是ImportSelector的实现类的走向
 this.importStack.registerImport(
   currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
 //加载到本地Map存储 
 processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
//processConfigurationClass最后
//存储到本地map     
this.configurationClasses.put(configClass, configClass); 

需要自动装配的类已经都存在本地的map中了,接下来应该就是晚容器中注册了

  • 再回到ConfigurationClassPostProcessor#processConfigBeanDefinitions
  • 前面的代码其实都是在分析parser.parse(candidates);,接下来走到后面这行
parser.parse(candidates);
parser.validate();
//public Set<ConfigurationClass> getConfigurationClasses() {
//  return this.configurationClasses.keySet();
// }
//取出存储需要注册的类 return this.configurationClasses.keySet();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);

// 取出reader 没有就创建
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//向容器注册
this.reader.loadBeanDefinitions(configClasses);

到这里,整个自动装配的流程就结束了,源码比较绕,需要很有耐心看 以上就是本章的全部内容了。

上一篇:SpringMvc源码分析第六弹 - 基于SpringMvc源码后的手写高仿版 下一篇:Springboot源码分析第二弹 - 自动配置实现

东隅已逝,桑榆非晚