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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 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(),所以学会看源码,才能看清本质。



目录
相关文章
|
1月前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
150 0
|
19天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
18天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
1月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
26 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
1月前
|
JSON 前端开发 JavaScript
优雅!Spring Boot 3.3 实现职责链模式,轻松应对电商订单流程
本文介绍如何使用 Spring Boot 3.3 实现职责链模式,优化电商订单处理流程。通过将订单处理的各个环节(如库存校验、优惠券核验、支付处理等)封装为独立的处理器,并通过职责链将这些处理器串联起来,实现了代码的解耦和灵活扩展。具体实现包括订单请求类 `OrderRequest`、抽象处理器类 `OrderHandler`、具体处理器实现(如 `OrderValidationHandler`、`VerifyCouponHandler` 等)、以及初始化职责链的配置类 `OrderChainConfig`。
|
1月前
|
机器学习/深度学习 移动开发 自然语言处理
基于人工智能技术的智能导诊系统源码,SpringBoot作为后端服务的框架,提供快速开发,自动配置和生产级特性
当身体不适却不知该挂哪个科室时,智能导诊系统应运而生。患者只需选择不适部位和症状,系统即可迅速推荐正确科室,避免排错队浪费时间。该系统基于SpringBoot、Redis、MyBatis Plus等技术架构,支持多渠道接入,具备自然语言理解和多输入方式,确保高效精准的导诊体验。无论是线上医疗平台还是大型医院,智能导诊系统均能有效优化就诊流程。
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
15 2
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
66 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
52 0

推荐镜像

更多