springboot启动核心源码分析-17

springboot启动核心源码分析

new SpringApplication(springboot2.class).run(args);

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //dk 根据类路径(所有jar)来推断当前容器的环境,none,servlet,reactive
        //dk 从下面的代码分析,如果所有jar包下能找到org.springframework.web.reactive.DispatcherHandler=》reactive
        //dk存在javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"
        //则为servlet,否则就是none
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //dk 加载所有jar路径下的META-INF/spring.factories配置文件,具体分析如下
        //dk 同时将ApplicationContextInitializer类型对应的value组成一个集合,7个初始器
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //dk 设置监听器,listeners有值了,11个监听器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        //dk 推断出当前主函数
        this.mainApplicationClass = deduceMainApplicationClass();
    }

推断的具体代码

static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
                && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
            return WebApplicationType.REACTIVE;
        }
        for (String className : SERVLET_INDICATOR_CLASSES) {
            if (!ClassUtils.isPresent(className, null)) {
                return WebApplicationType.NONE;
            }
        }
        return WebApplicationType.SERVLET;
    }
​

注意:spring-core封装的方法

ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)

从47种基础类型判断当前class是否是其中的一种
clazz = commonClassCache.get(name);

从类路径获取当前的class,如果加载不到jvm则直接报错
return Class.forName(name, false, clToUse);

加载所有jar下的META-INF/spring.factories配置文件,并将其key-value放入properties

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        //dk set后面的参数很关键,
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        //dk 将ApplicationContextInitializer对应的value进行初始化
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        //dk 进行排序,initializers有值了
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

解析的核心代码

Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                UrlResource resource = new UrlResource(url);
                //dk 读取当前资源文件下的所以属性,一般有Initializers,Listeners,Import Listeners
                // Import Filters,EnableAutoConfiguration,Failure analyzers,providers
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                //dk 注意2级for循环结束后,代表一个文件资源的所有key和value已经存放到result,当while结束后
                //dk 代表整个classpath路径下的文件都遍历完了,放到一个cache里面
                for (Map.Entry<?, ?> entry : properties.entrySet()) {
                //dk 获取7大key
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    //dk 分别将7大key对应的value放入result,注意result可以有多个,所以要循环来处理
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            cache.put(classLoader, result);

先初始化所有类路径下的的Initializer

spring-boot-autoconfigure下的配置

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
​

spring-boot下的配置

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

推断出主函数

private Class<?> deduceMainApplicationClass() {
        try {
            //dk 获取当前栈信息
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值