栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot启动流程详解(一)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot启动流程详解(一)

启动流程图(个人理解)

我们都是知道SpringBoot启动其实了类似下面的代码

自动定义启动类代码
@Configuration
@Component
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class StudySpringApplication {
	public static void main(String[] args) {
		SpringApplication.run(StudySpringApplication.class, args);
	}
}

其实里面较为核心代码是

SpringApplication.run(StudySpringApplication.class, args);
启动类源码

下面我们就开始对这个代码的源码进行分析
首先进到对应的方法里面

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

首先我们来解读下改方法上的注释
原文

Static helper that can be used to run a SpringApplication from the specified sources using default settings and user supplied arguments.
Params:
primarySources – the primary sources to load
args – the application arguments (usually passed from a Java main method)
Returns:
the running ApplicationContext

翻译后的(加上个人理解)
该静态方法主要根据用户提供主启动类和其他参数,实例化一个SpringApplication,并返回一个ApplicationContext
参数:
primarySources–要加载的主要源
args–应用程序参数(通常从Java主方法传递)
返回:
运行中的应用上下文(ApplicationContext)
上面的源码我们拆分成两部分来分析,
一、new SpringApplication(primarySources)实例化对象,
二、执行run(args)
下面我们看他们的具体源码,进行分析

实例化对象new SpringApplication(primarySources) 核心源码
	public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
		//赋值操作
		//要使用的资源加载器赋值
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		//核心启动类不能为空
		this.primarySources = new linkedHashSet<>(Arrays.asList(primarySources));
		//对应用类型赋值
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		//初始化集合赋值
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //监听器集合赋值
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		//获取主启动类集合
		this.mainApplicationClass = deduceMainApplicationClass();
	}
注释分析 注释原文
Create a new SpringApplication instance. The application context will load beans from the specified primary sources (see class-level documentation for details. The instance can be customized before calling run(String...).
Params:
resourceLoader – the resource loader to use
primarySources – the primary bean sources
See Also:
run(Class, String[]), setSources(Set)
翻译原文

创建一个新的SpringApplication实例。应用程序上下文将从指定的主源加载bean。可以在调用run(String…)之前自定义实例。
参数:
resourceLoader–要使用的资源加载器
primarySources–主要的bean源
该实例主要方法:
run(Class, String[]), setSources(Set)

源码拆解分析

对于资源加载器和主启动类属性赋值,较为简单没有分析必要

对应用类型赋值

SpringBoot启动时,在创建SpringApplication的构造方法内会调用枚举WebApplicationType的deduceFromClasspath方法获得应用类型并设置当前应用是普通web应用、响应式web应用还是非web应用。

	this.webApplicationType = WebApplicationType.deduceFromClasspath();

我们先看下webApplicationType都有哪些类型

	
	NONE,

	
	SERVLET,

	
	REACTIVE;

NONE:应用程序不作为web应用启动,不启动内嵌的服务。
SERVLET:应用程序以基于servlet的web应用启动,需启动内嵌servlet web服务。
REACTIVE:应用程序以响应式web应用启动,需启动内嵌的响应式web服务。

源码:

private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

	private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";

	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

	private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";

	private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
	
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;
	}

我们通过对上面的源码分析,发现它的核心方法是ClassUtils.isPresent()方法,该方法源码是

public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
        try {
            forName(className, classLoader);
            return true;
        } catch (IllegalAccessError var3) {
            throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" + className + "]: " + var3.getMessage(), var3);
        } catch (Throwable var4) {
            return false;
        }
    }

isPresent()方法调用了forName()方法,如果在调用forName()方法的过程中出现异常则返回false,也就是目标类不存在。否则,返回true。

 public static Class forName(String name, @Nullable ClassLoader classLoader) throws ClassNotFoundException, linkageError {
        Assert.notNull(name, "Name must not be null");
        Class clazz = resolvePrimitiveClassName(name);
        if (clazz == null) {
            clazz = (Class)commonClassCache.get(name);
        }

        if (clazz != null) {
            return clazz;
        } else {
            Class elementClass;
            String elementName;
            if (name.endsWith("[]")) {
                elementName = name.substring(0, name.length() - "[]".length());
                elementClass = forName(elementName, classLoader);
                return Array.newInstance(elementClass, 0).getClass();
            } else if (name.startsWith("[L") && name.endsWith(";")) {
                elementName = name.substring("[L".length(), name.length() - 1);
                elementClass = forName(elementName, classLoader);
                return Array.newInstance(elementClass, 0).getClass();
            } else if (name.startsWith("[")) {
                elementName = name.substring("[".length());
                elementClass = forName(elementName, classLoader);
                return Array.newInstance(elementClass, 0).getClass();
            } else {
                ClassLoader clToUse = classLoader;
                if (classLoader == null) {
                    clToUse = getDefaultClassLoader();
                }

                try {
                    return Class.forName(name, false, clToUse);
                } catch (ClassNotFoundException var9) {
                    int lastDotIndex = name.lastIndexOf(46);
                    if (lastDotIndex != -1) {
                        String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);

                        try {
                            return Class.forName(innerClassName, false, clToUse);
                        } catch (ClassNotFoundException var8) {
                        }
                    }
                    throw var9;
                }
            }
        }
    }
初始化集合赋值
	//初始化集合赋值
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

根据当前类名,去找到所有包含meta-INF/spring.factories的jar包,获取文件中该类名(ApplicationContextInitializer)为key值的value值

private  Collection getSpringFactoriesInstances(Class type) {
		return getSpringFactoriesInstances(type, new Class[] {});
	}
private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		//根据当前类名,去找到所有meta-INF/spring.factories的jar包,获取该类名为key值的value值
		Set names = new linkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//实例化获取的对象集合
		List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		//根据@Order注解进行排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
监听器集合赋值
 //监听器集合赋值
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

集合获取方法同上,根据当前类名,去找到所有meta-INF/spring.factories的jar包,获取该类名为key值的value值,然后返回根据@order注解排序后的实例化集合。

获取主启动类集合
this.mainApplicationClass = deduceMainApplicationClass();
执行run(args)方法

详见另外另一篇博客,地址如下
https://editor.csdn.net/md?not_checkout=1&articleId=123689089

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/777515.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号