SpringBoot源码学习笔记

本文详细介绍了SpringBoot的启动流程,从new SpringApplication到refresh方法的十三个子步骤,包括自动装配的实现机制。通过源码分析,揭示了SpringBoot如何初始化环境、配置bean工厂、注册监听器以及自动配置组件的过程。
摘要由CSDN通过智能技术生成

SpringBoot源码

版本:spring-boot-2.6.6

参考资料:

Spring源码全家桶教程56集IDEA版+mybatis源码精讲 哔哩哔哩_bilibili

SpringBoot基础-refresh方法解析_silly8543的博客-CSDN博客_refresh方法

一、流程图

在这里插入图片描述

二、流程

1.启动类

@SpringBootApplication
public class SpringbootstudyApplication {
   

    public static void main(String[] args) {
   
        SpringApplication.run(SpringbootstudyApplication.class, args);
    }

}

2.new SpringApplication

	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
   
        return run(new Class[]{
   primarySource}, args);
    }
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   
        return (new SpringApplication(primarySources)).run(args);
    }

创建当前项目的实例对象。

3.SpringApplication构造方法(初始化)

	public SpringApplication(Class<?>... primarySources) {
   
        this((ResourceLoader)null, primarySources);
    }
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = Collections.emptySet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        //资源加载器
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        //*解读1:判断应用程序类型
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        //*解读2:准备工作,获取初始化器
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //同初始化器,获取监听器
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        //设置程序运行主类
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

从启动类中加载bean相关信息。这个实例化的对象在被调用之前进行一些个性化操作(设置属性值)。

在这里插入图片描述


解读 1:判断类型

入口 SpringApplication构造方法:

this.webApplicationType = WebApplicationType.deduceFromClasspath();

deduceFromClasspath()判断这是什么类型的应用程序(none、servlet、react)。

static WebApplicationType deduceFromClasspath() {
   
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
   
            return REACTIVE;//1.REACTIVE
        } else {
   
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;

            for(int var2 = 0; var2 < var1; ++var2) {
   
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
   
                    return NONE;//2.NONE
                }
            }

            return SERVLET;//3.SERVLET, 默认是SERVLET
        }
    }

在这里插入图片描述

解读 2:getSpringFactoriesInstances

入口 SpringApplication构造方法:

this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

getSpringFactoriesInstances

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
   
        return this.getSpringFactoriesInstances(type, new Class[0]);
    }


    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
   
        //获取类加载器
        ClassLoader classLoader = this.getClassLoader();
        //*解读3
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

获取初始化器的实例对象集。

在这里插入图片描述

在这里插入图片描述

解读 3:spring.factories

入口 getSpringFactoriesInstances:

Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));

loadFactoryNames:

	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
   
        ...
        String factoryTypeName = factoryType.getName();
        //loadSpringFactories获取一个result结果集,拿到后getOrDefault获取当前工厂名的结果,即所有初始化器。
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
   
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
   
            return result;
        } else {
   
            HashMap result = new HashMap();

            try {
   
                //加载spring.factories中的属性值
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                //逐个获取属性值
                while(urls.hasMoreElements()) {
   
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
   
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
   
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
   
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
   
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                //返回result结果集
                return result;
            } catch (IOException var14) {
   
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

spring.factories:

# Logging Systems
org.springframework.boot.logging.LoggingSystemFactory=\
org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory,\
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory,\
org.springframework.boot.logging.java.JavaLoggingSystem.Factory

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

# ConfigData Location Resolvers
org.springframework.boot.context.config.ConfigDataLocationResolver=\
org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\
org.springframework.boot.context.config.StandardConfigDataLocationResolver

...


4.run方法

    public ConfigurableApplicationContext run(String... args) {
   
        //准备工作---------------------------------
        //计时器,记录开始时间
        long startTime = System.nanoTime();
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        //设置headless的属性并设置到系统属性中(java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true)
        this.configureHeadlessPrope
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值