Springboot源码:自动装配流程解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: Springboot源码:自动装配流程解析

前言

前面在写业务框架后,由于项目依赖的Spring IOC,单将该项目install后,在其它项目引入时,会找不到所依赖的Bean。所以利用Springboot的自动转配,在项目启动时加载Bean,并注册到IOC容器中。


Springboot自动装配可以说是SpringBoot自己定义的SPI机制,SPI 的全名为 Service Provider Interface ,SPI 思想 也可以叫做 SPI机制 ,它就是为某个接口寻找服务实现的机制。

正文

项目启动时,会传入启动类的Class对象,在创建完容器后,会将该传入的启动类注册包装成BeanDeifinition后注册到BeanFactory中。

    public static void main(String[] args) {
        //这里传入启动类对象
        SpringApplication.run(BtestApplication.class, args);
    }
  public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
        //这里存放启动类传入的Class对象
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.bootstrapRegistryInitializers = new ArrayList<>(
        getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
  }

BtestApplication.class 这个对象最终会被存入到primarySources属性集合中。

1:注册后置处理器

  public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
      }
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
      }
    }
    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    //注册ConfigurationClassPostProcessor 工厂后置处理器
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    //注册AutowiredAnnotationBeanPostProcessor 工厂后置处理器,用于处理器@Autowire等
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    //注册AutowiredAnnotationBeanPostProcessor 工厂后置处理器,用于处理器@Resoruce注解等
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition();
      try {
        def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
            AnnotationConfigUtils.class.getClassLoader()));
      }
      catch (ClassNotFoundException ex) {
        throw new IllegalStateException(
            "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
      }
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }
    return beanDefs;
  }

在创建ConfigurableApplicationContext上下文对象时,会往容器中注册Spring内部处理器类,包括后面需要用到的BeanFactoryPostProcessor,跟自动装配相关的是ConfigurationClassPostProcessor后置处理器。

2:注册启动类

  private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
        //设置系统环境参数
    context.setEnvironment(environment);
    postProcessApplicationContext(context);
    applyInitializers(context);
    listeners.contextPrepared(context);
    bootstrapContext.close(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 AbstractAutowireCapableBeanFactory) {
      ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
      if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory) beanFactory)
          .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
      }
    }
    if (this.lazyInitialization) {
      context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }
    context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
    // Load the sources
        //获取存放启动类Class对象的集合
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
        //将其注册到Bean工厂中
    load(context, sources.toArray(new Object[0]));
    listeners.contextLoaded(context);
  }
  public Set<Object> getAllSources() {
    Set<Object> allSources = new LinkedHashSet<>();
    if (!CollectionUtils.isEmpty(this.primarySources)) {
      allSources.addAll(this.primarySources);
    }
    if (!CollectionUtils.isEmpty(this.sources)) {
      allSources.addAll(this.sources);
    }
    return Collections.unmodifiableSet(allSources);
  }

在前面Spring将系统启动所传入的Class对象存入到了primarySources集合中,现将该集合中的对象获取出来并注册到BeanFactory工厂中,后续需要扫描该类的注解。

3:容器刷新

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      // 容器刷新前准备工作
      prepareRefresh();
      // Tell the subclass to refresh the internal bean factory.
      //创建Bean工厂,解析配置
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // bean工厂准备工作
      prepareBeanFactory(beanFactory);
      try {
        //拓展接口,留给子类进行实现拓展
        postProcessBeanFactory(beanFactory);
        // 注册执行,BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);
        // 注册创建BeanPostProcessor
        registerBeanPostProcessors(beanFactory);
        // 这个方法主要作用就是使用国际化,定制不同的消息文本,比如定义了一个Person的Bean,它有name属性,我们需要在不同的国家展示对应国家所在语言名称,这时候就可以使用国际化了。
        initMessageSource();
        // Initialize event multicaster for this context.
        //初始化应用事件广播器
        initApplicationEventMulticaster();
        // Initialize other special beans in specific context subclasses.
        //拓展接口,留给子类进行实现拓展,springboot就对该方法进行了处理
        onRefresh();
        // Check for listener beans and register them.
        //将内部的、以及我们自定义的监听器添加到缓存中,为后续逻辑处理做准备。还有添加事件源到缓存中。
        registerListeners();
        // Instantiate all remaining (non-lazy-init) singletons.
        //实例化剩下非懒加载的Bean
        finishBeanFactoryInitialization(beanFactory);
        // Last step: publish corresponding event.
        //使用应用事件广播器推送上下文刷新完毕事件(ContextRefreshedEvent )到相应的监听器。
        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 {
        // Reset common introspection caches in Spring's core, since we
        // might not ever need metadata for singleton beans anymore...
        resetCommonCaches();
      }
    }
  }

前面步骤都是基本准备工作,创建完上下文对象之后,调用Spring IOC的核心流程,完成Bean的扫描注册、实例化、初始化工作。笔者前面写了16篇Spring IOC的流程文章,有兴趣可以看一下。

4:执行BeanFactory后置处理器

在步骤1中,已经往BeanFactory工厂中注册了一个ConfigurationClassPostProcessor后置处理器


9a1e19dbc7959b1b469cf4036661e5b.png

该后置处理器实现了BeanDefinitionRegistryPostProcessor接口,所以最终会调用其postProcessBeanDefinitionRegistry方法。


该方法主要作用:


1、获取所有的BeanDefinition,挨个循环判断


2、对@Componet、@PropertySources、@ComponentScans、@Import、@ImportResource进行解析处理


我们启动类配置了@SpringBootApplication注解,@SpringBootApplication注解信息如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@EnableAutoConfiguration:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

由于启动类配置了@Import注解,所以会动@Import进行解析操作

5: @Import解析处理

  private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
      Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
      boolean checkForCircularImports) {
    if (importCandidates.isEmpty()) {
      return;
    }
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
      this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
      this.importStack.push(configClass);
      try {
        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);
            }
                        //如果Import选择器 实现了DeferredImportSelector接口,则添加到容器里面。后续会调用其getAutoConfigurationEntry方法
            if (selector instanceof DeferredImportSelector) {
              this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
            }
            else {
                            //调用Import选择器的selectImports方法,返回需要注册的BeanName
              String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
              Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
              processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
            }
          }
          else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
            // Candidate class is an ImportBeanDefinitionRegistrar ->
            // delegate to it to register additional bean definitions
            Class<?> candidateClass = candidate.loadClass();
            ImportBeanDefinitionRegistrar registrar =
                ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                    this.environment, this.resourceLoader, this.registry);
            configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
          }
          else {
            // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
            // process it as an @Configuration class
            this.importStack.registerImport(
                currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
            processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
          }
        }
      }
      catch (BeanDefinitionStoreException ex) {
        throw ex;
      }
      catch (Throwable ex) {
        throw new BeanDefinitionStoreException(
            "Failed to process import candidates for configuration class [" +
            configClass.getMetadata().getClassName() + "]", ex);
      }
      finally {
        this.importStack.pop();
      }
    }
  }

由于启动类配置的Import是AutoConfigurationImportSelector类,而该类实现了DeferredImportSelector接口,所以不会直接调用其selectImports方法,网上有很多文章说是掉这个方法进来的,其实并不是。如果实现了DeferredImportSelector接口,会将该Selector实现类加入到集合中,在后续调用其getAutoConfigurationEntry()方法;

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
    ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
} 

6:getAutoConfigurationEntry解析

  protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //获取META/INF/spring.factories
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
  }

getCandidateConfigurations(annotationMetadata, attributes),见方法1详解

方法1:getCandidateConfigurations

该方法会加载META-INF/spring.factories目录下的文件,并获取文件KEY为org.springframework.boot.autoconfigure.EnableAutoConfiguration的所有配置类。

  protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = new ArrayList<>(
        SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
    ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
    Assert.notEmpty(configurations,
        "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
            + "are using a custom packaging, make sure that file is correct.");
    return configurations;
  }

SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()),见方法2详解

方法2:loadFactoryNames

  public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    ClassLoader classLoaderToUse = classLoader;
    if (classLoaderToUse == null) {
      classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    }
        //factoryTypeName=org.springframework.boot.autoconfigure.EnableAutoConfiguration
    String factoryTypeName = factoryType.getName();
        //加载获有的配置类放到缓存中,并从中获取KEY为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置类
    return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
  }
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 {
            //FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
      Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
            //加载配置文件中的所有KEY-VELUE配置类,并将其放入缓存中
      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)));
      cache.put(classLoader, result);
    }
    catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
          FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
    return result;
  }

只要我们在META-INF/目录下的spring.factories文件中配置key为org.springframework.boot.autoconfigure.EnableAutoConfiguration,值为我们需要注入的自动装配类,Springboot会将该类包装成BeanDefinition并注入到IOC容器中;

总结

使用Spring开发时,由于项目中某些类需要提前注入到IOC容器中时,我们可以利用Springboot的自动装配,遵守其约定,将自动装配类配置到META-INF/目录下的spring.factories文件中,并指定key为org.springframework.boot.autoconfigure.EnableAutoConfiguration。这样Springboot就可以将该类注入到IOC容器中。


如果一个ImportSelector实现类,实现了DeferredImportSelector接口,那么该ImportSelector并不会调用selectImports()方法,而是直接调用getAutoConfigurationEntry()方法,网上有很多文章直接说入口是selectImports(),所以学会看源码,才能看清本质。



目录
相关文章
|
11天前
|
缓存 前端开发 中间件
[go 面试] 前端请求到后端API的中间件流程解析
[go 面试] 前端请求到后端API的中间件流程解析
|
3天前
|
人工智能 PyTorch 算法框架/工具
Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
【8月更文挑战第6天】Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
Xinference实战指南:全面解析LLM大模型部署流程,携手Dify打造高效AI应用实践案例,加速AI项目落地进程
|
4天前
|
存储 缓存 网络协议
DNS的执行流程是什么?
【8月更文挑战第15天】DNS的执行流程是什么?
15 1
|
5天前
|
NoSQL 关系型数据库 MySQL
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
14 2
|
22天前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
59 11
|
1天前
|
SQL 数据库 数据库管理
SQL查询是否都需要解析:深入解析SQL执行流程与优化技巧
在数据库管理系统中,SQL(Structured Query Language)查询是用户与数据库交互的主要方式
|
4天前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - SpringBoot 完整实现 Demo 附源码【完结篇】
ElasticSearch 实现分词全文检索 - SpringBoot 完整实现 Demo 附源码【完结篇】
11 0
|
17天前
|
Web App开发 JavaScript 前端开发
WebKit工作流程解析
WebKit的工作流程涉及将网页内容从HTML、CSS和JavaScript等源码转换为用户可以交互和观看的图像和文本。
13 0
|
14天前
|
存储 NoSQL Redis
redis 6源码解析之 object
redis 6源码解析之 object
42 6
|
7天前
|
开发者 Python
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
30 1

热门文章

最新文章

推荐镜像

更多